Fix parameter encryption for NVRAM commands

* Make sure hmac buffer space is reserved
* Add name computation for NV handles, modify TPM2_GetName
* Make TPM2_GetName handle multiple TPM Handle types
* Add wolfTPM2_SetNameHandle for passing handle name to parameter encryption
* Compute fresh NV Index Name during NVWrite with updated nvPublic information
* Compute fresh NV Index Name during NVRead, the same way NVWrite needs it

The NV_WRITTEN flag is being set, when there are consequtive reads, which
forces the hash to update. In order for this to take place, we need to
read the current(fresh) nvPublic information using TPM2_NV_ReadPublic.

* Add wolfTPM2_UnsetAuth to clear past authorization sessions when not needed

A way to clear auth sessions that are no longer needed was missing.

For example, after a TPM2_NVRead which uses two auth session slots, there
was no way for the user to clear the second slot afterwards. The only
possibility before was to overwrite with invalid values.

This way a TPM2_NVUndefineSpace would fail right after TPM2_NVRead, just
because there was an auth session not prevously cleared. This can be
handled either by the user manually or the user can use wolfTPM2 wrappers
that handle it now automatically using wolfTPM2_UnsetAuth.

Signed-off-by: Dimitar Tomov <dimi@wolfssl.com>
pull/145/head
Dimitar Tomov 2021-02-18 19:06:10 +02:00
parent df0107605e
commit 87e29005bf
5 changed files with 203 additions and 7 deletions

View File

@ -108,7 +108,8 @@ static int TPM2_CommandProcess(TPM2_CTX* ctx, TPM2_Packet* packet,
int rc = TPM_RC_SUCCESS;
UINT32 authSz;
BYTE *param, *encParam = NULL;
int paramSz, encParamSz = 0, authPos, i;
int paramSz, encParamSz = 0;
int i, authPos, handlePos;
/* Skip the header and handles area */
packet->pos = TPM2_HEADER_SIZE + (info->inHandleCnt * sizeof(TPM_HANDLE));
@ -187,9 +188,16 @@ static int TPM2_CommandProcess(TPM2_CTX* ctx, TPM2_Packet* packet,
}
#ifndef WOLFTPM2_NO_WOLFCRYPT
rc = TPM2_GetName(ctx, info->inHandleCnt, 0, &name1);
rc |= TPM2_GetName(ctx, info->inHandleCnt, 1, &name2);
rc |= TPM2_GetName(ctx, info->inHandleCnt, 2, &name3);
UINT32 handleValue;
handlePos = packet->pos;
packet->pos = TPM2_HEADER_SIZE; /* Handles are right after header */
TPM2_Packet_ParseU32(packet, &handleValue);
packet->pos = handlePos;
rc = TPM2_GetName(ctx, handleValue, info->inHandleCnt, 0, &name1);
rc |= TPM2_GetName(ctx, handleValue, info->inHandleCnt, 1, &name2);
rc |= TPM2_GetName(ctx, handleValue, info->inHandleCnt, 2, &name3);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("Error getting names for cpHash!\n");
@ -5269,7 +5277,7 @@ int TPM2_GetNonce(byte* nonceBuf, int nonceSz)
}
/* Get name for object/handle */
int TPM2_GetName(TPM2_CTX* ctx, int handleCnt, int idx, TPM2B_NAME* name)
int TPM2_GetName(TPM2_CTX* ctx, UINT32 handleValue, int handleCnt, int idx, TPM2B_NAME* name)
{
TPM2_AUTH_SESSION* session;
@ -5279,10 +5287,28 @@ int TPM2_GetName(TPM2_CTX* ctx, int handleCnt, int idx, TPM2B_NAME* name)
return TPM_RC_SUCCESS;
session = &ctx->session[idx];
#if 0
if (session->name.size > 0) {
name->size = session->name.size;
XMEMCPY(name->name, session->name.name, name->size);
}
(void)handleValue;
#else
if ((handleValue >= TRANSIENT_FIRST) ||
(handleValue >= NV_INDEX_FIRST && handleValue <= NV_INDEX_LAST)) {
if (session->name.size > 0) {
name->size = session->name.size;
XMEMCPY(name->name, session->name.name, name->size);
}
}
else {
handleValue = TPM2_Packet_SwapU32(handleValue);
name->size = sizeof(handleValue);
XMEMCPY(name->name, (byte*)&handleValue, name->size);
}
#endif
#ifdef WOLFTPM_DEBUG_VERBOSE
printf("Name %d: %d\n", idx, name->size);
TPM2_PrintBin(name->name, name->size);
@ -5649,6 +5675,67 @@ UINT16 TPM2_GetVendorID(void)
return vid;
}
/* Stores nameAlg + the digest of nvPublic in buffer, total size in size */
int TPM2_HashNvPublic(TPMS_NV_PUBLIC* nvPublic, byte* buffer, UINT16* size)
{
int rc;
#ifndef WOLFTPM2_NO_WOLFCRYPT
int hashSize, nameAlgValue, nameAlgSize;
wc_HashAlg hash;
enum wc_HashType hashType;
byte appending[sizeof(TPMS_NV_PUBLIC)];
TPM2B_DIGEST digest;
TPM2_Packet packet;
/* Prepare temporary buffer */
packet.buf = appending;
packet.pos = 0;
packet.size = sizeof(appending);
/* nvPublic must be in Marshaled state for hashing */
TPM2_Packet_AppendU32(&packet, nvPublic->nvIndex);
TPM2_Packet_AppendU16(&packet, nvPublic->nameAlg);
TPM2_Packet_AppendU32(&packet, nvPublic->attributes);
TPM2_Packet_AppendU16(&packet, nvPublic->authPolicy.size);
TPM2_Packet_AppendBytes(&packet, nvPublic->authPolicy.buffer,
nvPublic->authPolicy.size);
TPM2_Packet_AppendU16(&packet, nvPublic->dataSize);
/* Hashing nvPublic */
rc = TPM2_GetHashType(nvPublic->nameAlg);
hashType = (enum wc_HashType)rc;
rc = wc_HashGetDigestSize(hashType);
if (rc < 0) {
return rc;
}
hashSize = rc;
rc = wc_HashInit(&hash, hashType);
if(rc == 0) {
rc = wc_HashUpdate(&hash, hashType, packet.buf, packet.pos);
}
if (rc == 0) {
rc = wc_HashFinal(&hash, hashType, digest.buffer);
}
if (rc == 0) {
nameAlgValue = TPM2_Packet_SwapU16(nvPublic->nameAlg);
nameAlgSize = sizeof(nvPublic->nameAlg);
XMEMCPY(buffer, (byte*)&nameAlgValue, nameAlgSize);
XMEMCPY(&buffer[2], digest.buffer, hashSize);
/* account for nameAlg concatenation */
*size = hashSize + nameAlgSize;
}
wc_HashFree(&hash, hashType);
return TPM_RC_SUCCESS;
#else
return TPM_RC_FAILURE;
#endif
}
#ifdef DEBUG_WOLFTPM
#define LINE_LEN 16
void TPM2_PrintBin(const byte* buffer, word32 length)

View File

@ -320,7 +320,9 @@ void TPM2_Packet_AppendAuthCmd(TPM2_Packet* packet, TPMS_AUTH_COMMAND* authCmd)
if (packet == NULL || authCmd == NULL)
return;
#ifdef WOLFTPM_DEBUG_VERBOSE
TPM2_PrintAuth(authCmd);
#endif
/* make sure continueSession is set for TPM_RS_PW */
if (authCmd->sessionHandle == TPM_RS_PW &&

View File

@ -26,6 +26,11 @@
/* For some struct to buffer conversions */
#include <wolftpm/tpm2_packet.h>
#ifndef WOLFTPM2_NO_WOLFCRYPT
/* Required in wolfTPM2_CreateAuth() for name computation of NV handles */
#include <wolfssl/wolfcrypt/hash.h>
#endif
/* Local Functions */
static int wolfTPM2_GetCapabilities_NoDev(WOLFTPM2_CAPS* cap);
@ -369,6 +374,20 @@ int wolfTPM2_GetCapabilities(WOLFTPM2_DEV* dev, WOLFTPM2_CAPS* cap)
return wolfTPM2_GetCapabilities_NoDev(cap);
}
int wolfTPM2_UnsetAuth(WOLFTPM2_DEV* dev, int index)
{
TPM2_AUTH_SESSION* session;
if (dev == NULL || index >= MAX_SESSION_NUM) {
return BAD_FUNC_ARG;
}
session = &dev->session[index];
XMEMSET(session, 0, sizeof(TPM2_AUTH_SESSION));
return TPM2_SetSessionAuth(dev->session);
}
int wolfTPM2_SetAuth(WOLFTPM2_DEV* dev, int index,
TPM_HANDLE sessionHandle, const TPM2B_AUTH* auth,
TPMA_SESSION sessionAttributes, const TPM2B_NAME* name)
@ -415,6 +434,24 @@ int wolfTPM2_SetAuthHandle(WOLFTPM2_DEV* dev, int index,
return wolfTPM2_SetAuth(dev, index, TPM_RS_PW, auth, 0, name);
}
int wolfTPM2_SetNameHandle(WOLFTPM2_DEV* dev, int index,
const WOLFTPM2_HANDLE* handle)
{
const TPM2B_NAME* name = NULL;
TPM2_AUTH_SESSION* session;
if (dev == NULL || handle == NULL || index >= MAX_SESSION_NUM) {
return BAD_FUNC_ARG;
}
name = &handle->name;
session = &dev->session[index];
session->name.size = name->size;
XMEMCPY(session->name.name, name->name, session->name.size);
return TPM_RC_SUCCESS;
}
int wolfTPM2_SetAuthSession(WOLFTPM2_DEV* dev, int index,
const WOLFTPM2_SESSION* tpmSession, TPMA_SESSION sessionAttributes)
{
@ -446,6 +483,15 @@ int wolfTPM2_SetAuthSession(WOLFTPM2_DEV* dev, int index,
session->nonceTPM.size = tpmSession->nonceTPM.size;
XMEMCPY(session->nonceTPM.buffer, tpmSession->nonceTPM.buffer,
session->nonceTPM.size);
/* Parameter Encryption session will have an hmac added later.
* Reserve space, the same way it was done for nonceCaller above.
*/
if (session->sessionHandle != TPM_RS_PW &&
((session->sessionAttributes & TPMA_SESSION_encrypt) ||
(session->sessionAttributes & TPMA_SESSION_decrypt))) {
session->auth.size = TPM2_GetHashDigestSize(session->authHash);
}
}
return rc;
}
@ -2524,6 +2570,7 @@ int wolfTPM2_NVCreateAuth(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
{
int rc;
NV_DefineSpace_In in;
TPM2B_NAME name;
if (dev == NULL || nv == NULL)
return BAD_FUNC_ARG;
@ -2533,6 +2580,7 @@ int wolfTPM2_NVCreateAuth(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
wolfTPM2_SetAuthHandle(dev, 0, parent);
}
XMEMSET(&name, 0, sizeof(name));
XMEMSET(&in, 0, sizeof(in));
in.authHandle = parent->hndl;
if (auth && authSz > 0) {
@ -2560,9 +2608,15 @@ int wolfTPM2_NVCreateAuth(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
return rc;
}
/* Compute NV Index name in case of parameter encryption */
rc = TPM2_HashNvPublic(&in.publicInfo.nvPublic, name.name, &name.size);
/* return new NV handle */
XMEMSET(nv, 0, sizeof(*nv));
nv->handle.hndl = (TPM_HANDLE)nvIndex;
nv->handle.auth = in.auth;
nv->handle.name.size = name.size;
XMEMCPY(&nv->handle.name.name, name.name, nv->handle.name.size);
#ifdef DEBUG_WOLFTPM
printf("TPM2_NV_DefineSpace: Auth 0x%x, Idx 0x%x, Attribs 0x%d, Size %d\n",
@ -2596,6 +2650,8 @@ int wolfTPM2_NVWriteAuth(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv,
int rc = TPM_RC_SUCCESS;
word32 pos = 0, towrite;
NV_Write_In in;
NV_ReadPublic_In inPublic;
NV_ReadPublic_Out outPublic;
if (dev == NULL || nv == NULL)
return BAD_FUNC_ARG;
@ -2605,6 +2661,27 @@ int wolfTPM2_NVWriteAuth(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv,
wolfTPM2_SetAuthHandle(dev, 0, &nv->handle);
}
XMEMSET((byte*)&inPublic, 0, sizeof(inPublic));
XMEMSET((byte*)&outPublic, 0, sizeof(outPublic));
/* Read the NV Index publicArea to have up to date NV Index Name */
inPublic.nvIndex = nv->handle.hndl;
rc = TPM2_NV_ReadPublic(&inPublic, &outPublic);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("Failed to read fresh NvPublic\n");
#endif
return TPM_RC_FAILURE;
}
/* Compute NV Index name in case of parameter encryption */
rc = TPM2_HashNvPublic(&outPublic.nvPublic.nvPublic,
(byte*)&nv->handle.name.name,
&nv->handle.name.size);
/* Necessary, because NVWrite has two handles, second is NV Index */
wolfTPM2_SetNameHandle(dev, 0, &nv->handle);
wolfTPM2_SetNameHandle(dev, 1, &nv->handle);
while (dataSz > 0) {
towrite = dataSz;
if (towrite > MAX_NV_BUFFER_SIZE)
@ -2629,7 +2706,8 @@ int wolfTPM2_NVWriteAuth(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv,
#ifdef DEBUG_WOLFTPM
printf("TPM2_NV_Write: Auth 0x%x, Idx 0x%x, Offset %d, Size %d\n",
(word32)in.authHandle, (word32)in.nvIndex, in.offset, in.data.size);
(word32)in.authHandle, (word32)in.nvIndex,
in.offset, in.data.size);
#endif
pos += towrite;
@ -2656,6 +2734,8 @@ int wolfTPM2_NVReadAuth(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv,
word32 pos = 0, toread, dataSz;
NV_Read_In in;
NV_Read_Out out;
NV_ReadPublic_In inPublic;
NV_ReadPublic_Out outPublic;
if (dev == NULL || nv == NULL || pDataSz == NULL)
return BAD_FUNC_ARG;
@ -2665,6 +2745,27 @@ int wolfTPM2_NVReadAuth(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv,
wolfTPM2_SetAuthHandle(dev, 0, &nv->handle);
}
XMEMSET((byte*)&inPublic, 0, sizeof(inPublic));
XMEMSET((byte*)&outPublic, 0, sizeof(outPublic));
/* Read the NV Index publicArea to have up to date NV Index Name */
inPublic.nvIndex = nv->handle.hndl;
rc = TPM2_NV_ReadPublic(&inPublic, &outPublic);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("Failed to read fresh NvPublic\n");
#endif
return TPM_RC_FAILURE;
}
/* Compute NV Index name in case of parameter encryption */
rc = TPM2_HashNvPublic(&outPublic.nvPublic.nvPublic,
(byte*)&nv->handle.name.name,
&nv->handle.name.size);
/* Necessary, because NVWrite has two handles, second is NV Index */
wolfTPM2_SetNameHandle(dev, 0, &nv->handle);
wolfTPM2_SetNameHandle(dev, 1, &nv->handle);
dataSz = *pDataSz;
while (dataSz > 0) {
@ -2773,6 +2874,9 @@ int wolfTPM2_NVDeleteAuth(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
/* set session auth for key */
if (dev->ctx.session) {
wolfTPM2_SetAuthHandle(dev, 0, parent);
/* Make sure no other auth sessions exist */
wolfTPM2_UnsetAuth(dev, 1);
wolfTPM2_UnsetAuth(dev, 2);
}
XMEMSET(&in, 0, sizeof(in));

View File

@ -2800,7 +2800,8 @@ WOLFTPM_API int TPM2_GetTpmCurve(int curveID);
WOLFTPM_API int TPM2_GetWolfCurve(int curve_id);
WOLFTPM_API int TPM2_ParseAttest(const TPM2B_ATTEST* in, TPMS_ATTEST* out);
WOLFTPM_LOCAL int TPM2_GetName(TPM2_CTX* ctx, int handleCnt, int idx, TPM2B_NAME* name);
WOLFTPM_LOCAL int TPM2_GetName(TPM2_CTX* ctx, UINT32 handleValue, int handleCnt, int idx, TPM2B_NAME* name);
WOLFTPM_API int TPM2_HashNvPublic(TPMS_NV_PUBLIC* nvPublic, byte* buffer, UINT16* size);
#ifdef WOLFTPM2_USE_WOLF_RNG
WOLFTPM_API int TPM2_GetWolfRng(WC_RNG** rng);

View File

@ -131,6 +131,7 @@ WOLFTPM_API int wolfTPM2_GetTpmDevId(WOLFTPM2_DEV* dev);
WOLFTPM_API int wolfTPM2_SelfTest(WOLFTPM2_DEV* dev);
WOLFTPM_API int wolfTPM2_GetCapabilities(WOLFTPM2_DEV* dev, WOLFTPM2_CAPS* caps);
WOLFTPM_API int wolfTPM2_UnsetAuth(WOLFTPM2_DEV* dev, int index);
WOLFTPM_API int wolfTPM2_SetAuth(WOLFTPM2_DEV* dev, int index,
TPM_HANDLE sessionHandle, const TPM2B_AUTH* auth, TPMA_SESSION sessionAttributes,
const TPM2B_NAME* name);
@ -138,6 +139,7 @@ WOLFTPM_API int wolfTPM2_SetAuthPassword(WOLFTPM2_DEV* dev, int index, const TPM
WOLFTPM_API int wolfTPM2_SetAuthHandle(WOLFTPM2_DEV* dev, int index, const WOLFTPM2_HANDLE* handle);
WOLFTPM_API int wolfTPM2_SetAuthSession(WOLFTPM2_DEV* dev, int index,
const WOLFTPM2_SESSION* tpmSession, TPMA_SESSION sessionAttributes);
WOLFTPM_API int wolfTPM2_SetNameHandle(WOLFTPM2_DEV* dev, int index, const WOLFTPM2_HANDLE* handle);
WOLFTPM_API int wolfTPM2_StartSession(WOLFTPM2_DEV* dev,
WOLFTPM2_SESSION* session, WOLFTPM2_KEY* tpmKey,