From f0540d688e8febcb08e0f01c3cd6ccc044757af8 Mon Sep 17 00:00:00 2001 From: Dimitar Tomov Date: Thu, 11 Mar 2021 14:08:30 +0200 Subject: [PATCH] Make NVRAM and Keygen examples store the encoded public key part to save space Before examples were always storing the maximum public key part size, using sizeof(TPM2B_PUBLIC), with many empty fields. This meant, always storing 616 bytes of public part, even if the public key part was less. * writekeyBlob/readKeyBlob use the actual size of public key part * NVRAM store/read use the actual size of the public key part * Minor fixes from peer review * Added comment to nvram/store about Host Endianness, per peer review * Added public API for appending/parsing TPM2B_PUBLIC to byte streams Signed-off-by: Dimitar Tomov --- examples/keygen/keygen.c | 6 ++--- examples/nvram/read.c | 27 ++++++++++++++++++---- examples/nvram/store.c | 29 ++++++++++++++++++++--- examples/tpm_test_keys.c | 50 +++++++++++++++++++++++++++++++++------- src/tpm2.c | 48 +++++++++++++++++++++++++++++++++++++- wolftpm/tpm2.h | 4 +++- 6 files changed, 144 insertions(+), 20 deletions(-) diff --git a/examples/keygen/keygen.c b/examples/keygen/keygen.c index 00f0848..5f192fd 100644 --- a/examples/keygen/keygen.c +++ b/examples/keygen/keygen.c @@ -70,7 +70,7 @@ static void usage(void) static int symChoice(const char* arg, TPM_ALG_ID* algSym, int* keyBits, char* symMode) { - unsigned long len = XSTRLEN(arg); + size_t len = XSTRLEN(arg); if (len != SYM_EXTRA_OPTS_LEN) { return TPM_RC_FAILURE; @@ -96,7 +96,7 @@ static int symChoice(const char* arg, TPM_ALG_ID* algSym, int* keyBits, } *keyBits = atoi(&arg[SYM_EXTRA_OPTS_KEY_BITS_POS]); - if(*keyBits != 128 && *keyBits != 256) { + if(*keyBits != 128 && *keyBits != 192 && *keyBits != 256) { return TPM_RC_FAILURE; } @@ -119,7 +119,7 @@ int TPM2_Keygen_Example(void* userCtx, int argc, char *argv[]) int bAIK = 1; int keyBits = 256; const char* outputFile = "keyblob.bin"; - unsigned long len = 0; + size_t len = 0; char symMode[] = "aesctr"; if (argc >= 2) { diff --git a/examples/nvram/read.c b/examples/nvram/read.c index 26442d0..41c58a2 100644 --- a/examples/nvram/read.c +++ b/examples/nvram/read.c @@ -67,6 +67,9 @@ int TPM2_NVRAM_Read_Example(void* userCtx, int argc, char *argv[]) int paramEncAlg = TPM_ALG_NULL; int partialRead = 0; int offset = 0; + /* Needed for TPM2_ParsePublic */ + byte pubAreaBuffer[sizeof(TPM2B_PUBLIC)]; + int pubAreaSize; if (argc >= 2) { if (XSTRNCMP(argv[1], "-?", 2) == 0 || @@ -137,16 +140,32 @@ int TPM2_NVRAM_Read_Example(void* userCtx, int argc, char *argv[]) XMEMCPY(nv.handle.auth.buffer, auth.buffer, auth.size); if (partialRead != PRIVATE_PART_ONLY) { - readSize = sizeof(keyBlob.pub); - printf("Trying to read %d bytes of public key part from NV\n", readSize); + readSize = sizeof(keyBlob.pub.size); + printf("Trying to read %d bytes of public key size marker\n", readSize); rc = wolfTPM2_NVReadAuth(&dev, &nv, TPM2_DEMO_NVRAM_STORE_INDEX, - (byte*)&keyBlob.pub, &readSize, 0); + (byte*)&keyBlob.pub.size, &readSize, 0); if (rc != 0) { printf("Was a public key part written? (see nvram/store)\n"); goto exit; } printf("Successfully read public key part from NV\n\n"); - offset = readSize; + offset += readSize; + + readSize = sizeof(UINT16) + keyBlob.pub.size; /* account for TPM2B size marker */ + printf("Trying to read %d bytes of public key part from NV\n", keyBlob.pub.size); + rc = wolfTPM2_NVReadAuth(&dev, &nv, TPM2_DEMO_NVRAM_STORE_INDEX, + pubAreaBuffer, &readSize, offset); + if (rc != 0) goto exit; + printf("Successfully read public key part from NV\n\n"); + offset += readSize; + + /* Necessary for storing the publicArea with the correct encoding */ + rc = TPM2_ParsePublic(&keyBlob.pub, pubAreaBuffer, sizeof(pubAreaBuffer), &pubAreaSize); + if (rc != TPM_RC_SUCCESS) { + printf("Decoding of PublicArea failed. Unable to extract correctly.\n"); + goto exit; + } + #ifdef WOLFTPM_DEBUG_VERBOSE TPM2_PrintPublicArea(&keyBlob.pub); printf("\n"); diff --git a/examples/nvram/store.c b/examples/nvram/store.c index b10e53e..e1796d0 100644 --- a/examples/nvram/store.c +++ b/examples/nvram/store.c @@ -68,6 +68,9 @@ int TPM2_NVRAM_Store_Example(void* userCtx, int argc, char *argv[]) int paramEncAlg = TPM_ALG_NULL; int partialStore = 0; int offset = 0; + /* Needed for TPM2_AppendPublic */ + byte pubAreaBuffer[sizeof(TPM2B_PUBLIC)]; + int pubAreaSize; if (argc >= 2) { if (XSTRNCMP(argv[1], "-?", 2) == 0 || @@ -147,12 +150,32 @@ int TPM2_NVRAM_Store_Example(void* userCtx, int argc, char *argv[]) TPM2_DEMO_NVRAM_STORE_INDEX); if (partialStore != PRIVATE_PART_ONLY) { - printf("Public part = %lu bytes\n", sizeof(keyBlob.pub)); + printf("Public part = %hu bytes\n", keyBlob.pub.size); rc = wolfTPM2_NVWriteAuth(&dev, &nv, TPM2_DEMO_NVRAM_STORE_INDEX, - (byte*)&keyBlob.pub, sizeof(keyBlob.pub), 0); + (byte*)&keyBlob.pub.size, sizeof(keyBlob.pub.size), 0); + if (rc != 0) goto exit; + printf("Stored 2-byte size marker before the private part\n"); + offset += sizeof(keyBlob.pub.size); + + /* Necessary for storing the publicArea with the correct byte encoding */ + rc = TPM2_AppendPublic(pubAreaBuffer, sizeof(pubAreaBuffer), &pubAreaSize, &keyBlob.pub); + /* Note: + * Public Area is the only part of a TPM key that can be stored encoded + * Private Area is stored as-is, because TPM2B_PRIVATE is byte buffer + * and UINT16 size field, while Public Area is a complex TCG structure. + */ + if (rc != TPM_RC_SUCCESS) { + printf("Encoding of the publicArea failed. Unable to store.\n"); + goto exit; + } + + /* The buffer holds pub.publicArea and also pub.size(UINT16) */ + rc = wolfTPM2_NVWriteAuth(&dev, &nv, TPM2_DEMO_NVRAM_STORE_INDEX, + pubAreaBuffer, sizeof(UINT16) + keyBlob.pub.size, offset); if (rc != 0) goto exit; printf("NV write of public part succeeded\n\n"); - offset = sizeof(keyBlob.pub); + offset += sizeof(UINT16) + keyBlob.pub.size; + #ifdef WOLFTPM_DEBUG_VERBOSE TPM2_PrintPublicArea(&keyBlob.pub); printf("\n"); diff --git a/examples/tpm_test_keys.c b/examples/tpm_test_keys.c index d68d337..dc15a76 100644 --- a/examples/tpm_test_keys.c +++ b/examples/tpm_test_keys.c @@ -42,11 +42,26 @@ int writeKeyBlob(const char* filename, #if !defined(NO_FILESYSTEM) && !defined(NO_WRITE_TEMP_FILES) XFILE fp = NULL; size_t fileSz = 0; + byte pubAreaBuffer[sizeof(TPM2B_PUBLIC)]; + int pubAreaSize; fp = XFOPEN(filename, "wb"); if (fp != XBADFILE) { - key->pub.size = sizeof(key->pub); - fileSz += XFWRITE(&key->pub, 1, sizeof(key->pub), fp); + /* Make publicArea in encoded format to eliminate empty fields, save space */ + rc = TPM2_AppendPublic(pubAreaBuffer, sizeof(pubAreaBuffer), &pubAreaSize, &key->pub); + if (rc != TPM_RC_SUCCESS) return rc; + if (pubAreaSize != (key->pub.size + sizeof(key->pub.size))) { +#ifdef DEBUG_WOLFTPM + printf("writeKeyBlob: Sanity check for publicArea size failed\n"); +#endif + return -1; + } + TPM2_PrintBin(pubAreaBuffer, pubAreaSize); + /* Write size marker for the public part */ + fileSz += XFWRITE(&key->pub.size, 1, sizeof(key->pub.size), fp); + /* Write the public part with bytes aligned */ + fileSz += XFWRITE(pubAreaBuffer, 1, sizeof(UINT16) + key->pub.size, fp); + /* Write the private part, size marker is included */ fileSz += XFWRITE(&key->priv, 1, sizeof(UINT16) + key->priv.size, fp); XFCLOSE(fp); } @@ -65,6 +80,8 @@ int readKeyBlob(const char* filename, WOLFTPM2_KEYBLOB* key) XFILE fp = NULL; size_t fileSz = 0; size_t bytes_read = 0; + byte pubAreaBuffer[sizeof(TPM2B_PUBLIC)]; + int pubAreaSize; XMEMSET(key, 0, sizeof(WOLFTPM2_KEYBLOB)); @@ -79,13 +96,29 @@ int readKeyBlob(const char* filename, WOLFTPM2_KEYBLOB* key) } printf("Reading %d bytes from %s\n", (int)fileSz, filename); - bytes_read = XFREAD(&key->pub, 1, sizeof(key->pub), fp); - if (bytes_read != sizeof(key->pub)) { - printf("Read %zu, expected public blob %zu bytes\n", bytes_read, sizeof(key->pub)); + bytes_read = XFREAD(&key->pub.size, 1, sizeof(key->pub.size), fp); + if (bytes_read != sizeof(key->pub.size)) { + printf("Read %zu, expected size marker of %zu bytes\n", bytes_read, sizeof(key->pub.size)); goto exit; } - if (fileSz > sizeof(key->pub)) { - fileSz -= sizeof(key->pub); + fileSz -= bytes_read; + + bytes_read = XFREAD(pubAreaBuffer, 1, sizeof(UINT16) + key->pub.size, fp); + if (bytes_read != sizeof(UINT16) + key->pub.size) { + printf("Read %zu, expected public blob %lu bytes\n", bytes_read, sizeof(UINT16) + key->pub.size); + goto exit; + } + fileSz -= bytes_read; /* Reminder bytes for private key part */ + + /* Decode the byte stream into a publicArea structure ready for use */ + rc = TPM2_ParsePublic(&key->pub, pubAreaBuffer, sizeof(pubAreaBuffer), &pubAreaSize); + if (rc != TPM_RC_SUCCESS) return rc; +#ifdef DEBUG_WOLFTPM + TPM2_PrintPublicArea(&key->pub); +#endif + + if (fileSz > 0) { + printf("Reading the private part of the key\n"); bytes_read = XFREAD(&key->priv, 1, fileSz, fp); if (bytes_read != fileSz) { printf("Read %zu, expected private blob %zu bytes\n", bytes_read, fileSz); @@ -95,7 +128,8 @@ int readKeyBlob(const char* filename, WOLFTPM2_KEYBLOB* key) } /* sanity check the sizes */ - if (key->pub.size != sizeof(key->pub) || key->priv.size > sizeof(key->priv.buffer)) { + if (pubAreaSize != (key->pub.size + sizeof(key->pub.size)) || + key->priv.size > sizeof(key->priv.buffer)) { printf("Struct size check failed (pub %d, priv %d)\n", key->pub.size, key->priv.size); rc = BUFFER_E; diff --git a/src/tpm2.c b/src/tpm2.c index 2ce263b..4f2098b 100644 --- a/src/tpm2.c +++ b/src/tpm2.c @@ -5733,6 +5733,52 @@ int TPM2_HashNvPublic(TPMS_NV_PUBLIC* nvPublic, byte* buffer, UINT16* size) #endif } +WOLFTPM_API int TPM2_AppendPublic(byte* buf, size_t size, int* sizeUsed, TPM2B_PUBLIC* pub) +{ + TPM2_Packet packet; + + if (buf == NULL || sizeUsed == NULL) + return BAD_FUNC_ARG; + + if (size < sizeof(TPM2B_PUBLIC)) { + printf("Insufficient buffer size for TPM2B_PUBLIC operations\n"); + return TPM_RC_FAILURE; + } + + /* Prepare temporary buffer */ + packet.buf = buf; + packet.pos = 0; + packet.size = (int)size; + + TPM2_Packet_AppendPublic(&packet, pub); + *sizeUsed = packet.pos; + + return TPM_RC_SUCCESS; +} + +WOLFTPM_API int TPM2_ParsePublic(TPM2B_PUBLIC* pub, byte* buf, size_t size, int* sizeUsed) +{ + TPM2_Packet packet; + + if (buf == NULL || sizeUsed == NULL) + return BAD_FUNC_ARG; + + if (size < sizeof(TPM2B_PUBLIC)) { + printf("Insufficient buffer size for TPM2B_PUBLIC operations\n"); + return TPM_RC_FAILURE; + } + + /* Prepare temporary buffer */ + packet.buf = buf; + packet.pos = 0; + packet.size = (int)size; + + TPM2_Packet_ParsePublic(&packet, pub); + *sizeUsed = packet.pos; + + return TPM_RC_SUCCESS; +} + #ifdef DEBUG_WOLFTPM #define LINE_LEN 16 void TPM2_PrintBin(const byte* buffer, word32 length) @@ -5864,7 +5910,7 @@ void TPM2_PrintPublicArea(const TPM2B_PUBLIC* pub) TPM2_PrintBin(pub->publicArea.unique.derive.context.buffer, pub->publicArea.unique.derive.context.size); break; } - + printf("\n"); } #endif diff --git a/wolftpm/tpm2.h b/wolftpm/tpm2.h index 4280823..2abfea2 100644 --- a/wolftpm/tpm2.h +++ b/wolftpm/tpm2.h @@ -2800,8 +2800,10 @@ 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, UINT32 handleValue, int handleCnt, int idx, TPM2B_NAME* name); WOLFTPM_API int TPM2_HashNvPublic(TPMS_NV_PUBLIC* nvPublic, byte* buffer, UINT16* size); +WOLFTPM_API int TPM2_AppendPublic(byte* buf, size_t size, int* sizeUsed, TPM2B_PUBLIC* pub); +WOLFTPM_API int TPM2_ParsePublic(TPM2B_PUBLIC* pub, byte* buf, size_t size, int* sizeUsed); +WOLFTPM_LOCAL int TPM2_GetName(TPM2_CTX* ctx, UINT32 handleValue, int handleCnt, int idx, TPM2B_NAME* name); #ifdef WOLFTPM2_USE_WOLF_RNG WOLFTPM_API int TPM2_GetWolfRng(WC_RNG** rng);