wolfTPM/src/tpm2_wrap.c

6967 lines
213 KiB
C

/* tpm2_wrap.c
*
* Copyright (C) 2006-2023 wolfSSL Inc.
*
* This file is part of wolfTPM.
*
* wolfTPM is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfTPM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#include <wolftpm/tpm2_wrap.h>
#include <wolftpm/tpm2_param_enc.h>
#ifndef WOLFTPM2_NO_WRAPPER
/* For some struct to buffer conversions */
#include <wolftpm/tpm2_packet.h>
/* Local Functions */
static int wolfTPM2_GetCapabilities_NoDev(WOLFTPM2_CAPS* cap);
static void wolfTPM2_CopySymmetric(TPMT_SYM_DEF* out, const TPMT_SYM_DEF* in);
static void wolfTPM2_CopyName(TPM2B_NAME* out, const TPM2B_NAME* in);
static void wolfTPM2_CopyAuth(TPM2B_AUTH* out, const TPM2B_AUTH* in);
static void wolfTPM2_CopyPubT(TPMT_PUBLIC* out, const TPMT_PUBLIC* in);
static void wolfTPM2_CopyPub(TPM2B_PUBLIC* out, const TPM2B_PUBLIC* in);
static void wolfTPM2_CopyPriv(TPM2B_PRIVATE* out, const TPM2B_PRIVATE* in);
static void wolfTPM2_CopyEccParam(TPM2B_ECC_PARAMETER* out, const TPM2B_ECC_PARAMETER* in);
static void wolfTPM2_CopyKeyFromBlob(WOLFTPM2_KEY* key, const WOLFTPM2_KEYBLOB* keyBlob);
static void wolfTPM2_CopyNvPublic(TPMS_NV_PUBLIC* out, const TPMS_NV_PUBLIC* in);
/******************************************************************************/
/* --- BEGIN Wrapper Device Functions -- */
/******************************************************************************/
static int wolfTPM2_Init_ex(TPM2_CTX* ctx, TPM2HalIoCb ioCb, void* userCtx,
int timeoutTries)
{
int rc;
#if !defined(WOLFTPM_LINUX_DEV) && !defined(WOLFTPM_WINAPI)
Startup_In startupIn;
#if defined(WOLFTPM_MICROCHIP) || defined(WOLFTPM_PERFORM_SELFTEST)
SelfTest_In selfTest;
#endif
#endif /* ! WOLFTPM_LINUX_DEV */
if (ctx == NULL)
return BAD_FUNC_ARG;
#if defined(WOLFTPM_LINUX_DEV) || defined(WOLFTPM_SWTPM) || \
defined(WOLFTPM_WINAPI)
rc = TPM2_Init_minimal(ctx);
/* Using standard file I/O for the Linux TPM device */
(void)ioCb;
(void)userCtx;
(void)timeoutTries;
#else
rc = TPM2_Init_ex(ctx, ioCb, userCtx, timeoutTries);
#endif
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_Init failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
#endif
return rc;
}
#ifdef DEBUG_WOLFTPM
printf("TPM2: Caps 0x%08x, Did 0x%04x, Vid 0x%04x, Rid 0x%2x \n",
ctx->caps,
ctx->did_vid >> 16,
ctx->did_vid & 0xFFFF,
ctx->rid);
#endif
#if !defined(WOLFTPM_LINUX_DEV) && !defined(WOLFTPM_WINAPI)
/* startup */
XMEMSET(&startupIn, 0, sizeof(Startup_In));
startupIn.startupType = TPM_SU_CLEAR;
rc = TPM2_Startup(&startupIn);
if (rc != TPM_RC_SUCCESS &&
rc != TPM_RC_INITIALIZE /* TPM_RC_INITIALIZE = Already started */ ) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_Startup failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
#endif
return rc;
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_Startup pass\n");
#endif
#if defined(WOLFTPM_MICROCHIP) || defined(WOLFTPM_PERFORM_SELFTEST)
/* Do full self-test (Chips such as ATTPM20 require this before some operations) */
XMEMSET(&selfTest, 0, sizeof(selfTest));
selfTest.fullTest = YES;
rc = TPM2_SelfTest(&selfTest);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_SelfTest failed 0x%x: %s\n", rc, TPM2_GetRCString(rc));
#endif
return rc;
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_SelfTest pass\n");
#endif
#else
rc = TPM_RC_SUCCESS;
#endif /* WOLFTPM_MICROCHIP || WOLFTPM_PERFORM_SELFTEST */
#endif /* !WOLFTPM_LINUX_DEV && !WOLFTPM_WINAPI */
return rc;
}
/* Single-shot API for testing access to hardware and optionally return capabilities */
int wolfTPM2_Test(TPM2HalIoCb ioCb, void* userCtx, WOLFTPM2_CAPS* caps)
{
int rc;
TPM2_CTX* current_ctx;
TPM2_CTX ctx;
/* Backup active TPM context */
current_ctx = TPM2_GetActiveCtx();
/* Perform startup and test device */
rc = wolfTPM2_Init_ex(&ctx, ioCb, userCtx, TPM_STARTUP_TEST_TRIES);
if (rc != TPM_RC_SUCCESS) {
return rc;
}
/* Optionally get and return capabilities */
if (caps) {
rc = wolfTPM2_GetCapabilities_NoDev(caps);
}
/* Perform cleanup */
TPM2_Cleanup(&ctx);
/* Restore original context */
TPM2_SetActiveCtx(current_ctx);
return rc;
}
int wolfTPM2_Init(WOLFTPM2_DEV* dev, TPM2HalIoCb ioCb, void* userCtx)
{
int rc;
if (dev == NULL)
return BAD_FUNC_ARG;
XMEMSET(dev, 0, sizeof(WOLFTPM2_DEV));
rc = wolfTPM2_Init_ex(&dev->ctx, ioCb, userCtx, TPM_TIMEOUT_TRIES);
if (rc != TPM_RC_SUCCESS) {
return rc;
}
/* define the default session auth */
XMEMSET(dev->session, 0, sizeof(dev->session));
wolfTPM2_SetAuthPassword(dev, 0, NULL);
return rc;
}
#ifndef WOLFTPM2_NO_HEAP
WOLFTPM2_DEV* wolfTPM2_New(void)
{
WOLFTPM2_DEV *dev = (WOLFTPM2_DEV*)XMALLOC(
sizeof(WOLFTPM2_DEV), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (dev != NULL) {
if (wolfTPM2_Init(dev, NULL, NULL) != TPM_RC_SUCCESS) {
XFREE(dev, NULL, DYNAMIC_TYPE_TMP_BUFFER);
dev = NULL;
}
}
return dev;
}
int wolfTPM2_Free(WOLFTPM2_DEV *dev)
{
if (dev != NULL) {
wolfTPM2_Cleanup(dev);
XFREE(dev, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
return TPM_RC_SUCCESS;
}
WOLFTPM2_KEYBLOB* wolfTPM2_NewKeyBlob(void)
{
WOLFTPM2_KEYBLOB* blob = (WOLFTPM2_KEYBLOB*)XMALLOC(
sizeof(WOLFTPM2_KEYBLOB), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (blob != NULL) {
XMEMSET(blob, 0, sizeof(WOLFTPM2_KEYBLOB));
}
return blob;
}
int wolfTPM2_FreeKeyBlob(WOLFTPM2_KEYBLOB* blob)
{
if (blob != NULL) {
XFREE(blob, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
return TPM_RC_SUCCESS;
}
TPMT_PUBLIC* wolfTPM2_NewPublicTemplate(void)
{
TPMT_PUBLIC* PublicTemplate = (TPMT_PUBLIC*)XMALLOC(
sizeof(TPMT_PUBLIC), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (PublicTemplate != NULL) {
XMEMSET(PublicTemplate, 0, sizeof(TPMT_PUBLIC));
}
return PublicTemplate;
}
int wolfTPM2_FreePublicTemplate(TPMT_PUBLIC* PublicTemplate)
{
if (PublicTemplate != NULL) {
XFREE(PublicTemplate, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
return TPM_RC_SUCCESS;
}
WOLFTPM2_KEY* wolfTPM2_NewKey(void)
{
WOLFTPM2_KEY* key = (WOLFTPM2_KEY*)XMALLOC(
sizeof(WOLFTPM2_KEY), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (key != NULL) {
XMEMSET(key, 0, sizeof(WOLFTPM2_KEY));
}
return key;
}
int wolfTPM2_FreeKey(WOLFTPM2_KEY* key)
{
if (key != NULL) {
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
return TPM_RC_SUCCESS;
}
WOLFTPM2_SESSION* wolfTPM2_NewSession(void)
{
WOLFTPM2_SESSION* session = (WOLFTPM2_SESSION*)XMALLOC(
sizeof(WOLFTPM2_SESSION), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (session != NULL) {
XMEMSET(session, 0, sizeof(WOLFTPM2_SESSION));
}
return session;
}
int wolfTPM2_FreeSession(WOLFTPM2_SESSION* session)
{
if (session != NULL) {
XFREE(session, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
return TPM_RC_SUCCESS;
}
#ifdef WOLFTPM2_CERT_GEN
WOLFTPM2_CSR* wolfTPM2_NewCSR(void)
{
WOLFTPM2_CSR* csr = (WOLFTPM2_CSR*)XMALLOC(
sizeof(WOLFTPM2_CSR), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (csr != NULL) {
XMEMSET(csr, 0, sizeof(WOLFTPM2_CSR));
if (wc_InitCert(&csr->req) != 0) {
XFREE(csr, NULL, DYNAMIC_TYPE_TMP_BUFFER);
csr = NULL;
}
}
return csr;
}
int wolfTPM2_FreeCSR(WOLFTPM2_CSR* csr)
{
if (csr != NULL) {
XFREE(csr, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
return TPM_RC_SUCCESS;
}
#endif /* WOLFTPM2_CERT_GEN */
#endif /* !WOLFTPM2_NO_HEAP */
WOLFTPM2_HANDLE* wolfTPM2_GetHandleRefFromKey(WOLFTPM2_KEY* key)
{
return (key != NULL) ? &key->handle : NULL;
}
WOLFTPM2_HANDLE* wolfTPM2_GetHandleRefFromKeyBlob(WOLFTPM2_KEYBLOB* keyBlob)
{
return (keyBlob != NULL) ? &keyBlob->handle : NULL;
}
WOLFTPM2_HANDLE* wolfTPM2_GetHandleRefFromSession(WOLFTPM2_SESSION* session)
{
return (session != NULL) ? &session->handle : NULL;
}
TPM_HANDLE wolfTPM2_GetHandleValue(WOLFTPM2_HANDLE* handle)
{
TPM_HANDLE hndl = 0;
if (handle)
hndl = handle->hndl;
return hndl;
}
int wolfTPM2_GetKeyBlobAsBuffer(byte *buffer, word32 bufferSz,
WOLFTPM2_KEYBLOB* key)
{
int rc = 0;
int sz = 0;
byte pubAreaBuffer[sizeof(TPM2B_PUBLIC)];
int pubAreaSize;
if (key == NULL) {
return BAD_FUNC_ARG;
}
/* publicArea is encoded format. Eliminates empty fields, saves space. */
rc = TPM2_AppendPublic(pubAreaBuffer, (word32)sizeof(pubAreaBuffer),
&pubAreaSize, &key->pub);
if (rc != TPM_RC_SUCCESS) {
return rc;
}
if (pubAreaSize != (key->pub.size + (int)sizeof(key->pub.size))) {
#ifdef DEBUG_WOLFTPM
printf("Sanity check for publicArea size failed\n");
#endif
return BUFFER_E;
}
/* calculate actual size */
sz = sizeof(key->pub.size) + sizeof(UINT16) + key->pub.size +
sizeof(UINT16) + key->priv.size;
/* return size only */
if (buffer == NULL) {
return sz;
}
if ((int)bufferSz < sz) {
return BUFFER_E;
}
/* Write size marker for the public part */
XMEMCPY(buffer, &key->pub.size, sizeof(key->pub.size));
sz = sizeof(key->pub.size);
/* Write the public part with bytes aligned */
XMEMCPY(buffer + sz, pubAreaBuffer, sizeof(UINT16) + key->pub.size);
sz += sizeof(UINT16) + key->pub.size;
/* Write the private part, size marker is included */
XMEMCPY(buffer + sz, &key->priv, sizeof(UINT16) + key->priv.size);
sz += sizeof(UINT16) + key->priv.size;
#ifdef WOLFTPM_DEBUG_VERBOSE
printf("Get KeyBlob: %d bytes\n", (int)sz);
TPM2_PrintBin(buffer, sz);
#endif
return sz;
}
int wolfTPM2_GetKeyBlobAsSeparateBuffers(byte* pubBuffer, word32* pubBufferSz,
byte* privBuffer, word32* privBufferSz, WOLFTPM2_KEYBLOB* key)
{
int rc = 0;
byte pubAreaBuffer[sizeof(TPM2B_PUBLIC)];
int pubAreaSize;
if (key == NULL || pubBufferSz == NULL || privBufferSz == NULL) {
return BAD_FUNC_ARG;
}
/* publicArea is encoded format. Eliminates empty fields, saves space. */
rc = TPM2_AppendPublic(pubAreaBuffer, (word32)sizeof(pubAreaBuffer),
&pubAreaSize, &key->pub);
if (rc != TPM_RC_SUCCESS) {
return rc;
}
if (pubAreaSize != (key->pub.size + (int)sizeof(key->pub.size))) {
#ifdef DEBUG_WOLFTPM
printf("Sanity check for publicArea size failed\n");
#endif
return BUFFER_E;
}
if (pubBuffer == NULL || privBuffer == NULL) {
*privBufferSz = sizeof(UINT16) + key->priv.size;
*pubBufferSz = sizeof(key->pub.size) + sizeof(UINT16) + key->pub.size;
return LENGTH_ONLY_E;
}
if (*pubBufferSz < sizeof(key->pub.size) + sizeof(UINT16) + key->pub.size ||
*privBufferSz < sizeof(UINT16) + key->priv.size) {
return BUFFER_E;
}
*pubBufferSz = 0;
*privBufferSz = 0;
/* Write size marker for the public part */
XMEMCPY(pubBuffer, &key->pub.size, sizeof(key->pub.size));
*pubBufferSz += sizeof(key->pub.size);
/* Write the public part with bytes aligned */
XMEMCPY(pubBuffer + *pubBufferSz, pubAreaBuffer, sizeof(UINT16) +
key->pub.size);
*pubBufferSz += sizeof(UINT16) + key->pub.size;
/* Write the private part, size marker is included */
XMEMCPY(privBuffer, &key->priv, sizeof(UINT16) + key->priv.size);
*privBufferSz += sizeof(UINT16) + key->priv.size;
#ifdef WOLFTPM_DEBUG_VERBOSE
printf("Get KeyBlob public: %d bytes\n", (int)*pubBufferSz);
TPM2_PrintBin(pubBuffer, *pubBufferSz);
printf("Get KeyBlob private: %d bytes\n", (int)*privBufferSz);
TPM2_PrintBin(privBuffer, *privBufferSz);
#endif
return TPM_RC_SUCCESS;
}
int wolfTPM2_SetKeyBlobFromBuffer(WOLFTPM2_KEYBLOB* key, byte *buffer,
word32 bufferSz)
{
int rc = 0;
byte pubAreaBuffer[sizeof(TPM2B_PUBLIC)];
int pubAreaSize;
byte *runner = buffer;
size_t done_reading = 0;
if ((key == NULL) || (buffer == NULL) || (bufferSz <= 0)) {
return BAD_FUNC_ARG;
}
XMEMSET(key, 0, sizeof(WOLFTPM2_KEYBLOB));
#ifdef WOLFTPM_DEBUG_VERBOSE
printf("Set KeyBlob: %d bytes\n", (int)bufferSz);
TPM2_PrintBin(buffer, bufferSz);
#endif
if (bufferSz < done_reading + sizeof(key->pub.size)) {
#ifdef DEBUG_WOLFTPM
printf("Buffer size check failed (%d)\n", bufferSz);
#endif
return BUFFER_E;
}
XMEMCPY(&key->pub.size, runner, sizeof(key->pub.size));
runner += sizeof(key->pub.size);
done_reading += sizeof(key->pub.size);
if (bufferSz < done_reading + sizeof(UINT16) + key->pub.size) {
#ifdef DEBUG_WOLFTPM
printf("Buffer size check failed (%d)\n", bufferSz);
#endif
return BUFFER_E;
}
XMEMCPY(pubAreaBuffer, runner, sizeof(UINT16) + key->pub.size);
runner += sizeof(UINT16) + key->pub.size;
done_reading += sizeof(UINT16) + key->pub.size;
/* Decode the byte stream into a publicArea structure ready for use */
rc = TPM2_ParsePublic(&key->pub, pubAreaBuffer,
(word32)sizeof(pubAreaBuffer), &pubAreaSize);
if (rc != TPM_RC_SUCCESS) {
return rc;
}
if (bufferSz < done_reading + sizeof(key->priv.size)) {
#ifdef DEBUG_WOLFTPM
printf("Buffer size check failed (%d)\n", bufferSz);
#endif
return BUFFER_E;
}
XMEMCPY(&key->priv.size, runner, sizeof(key->priv.size));
runner += sizeof(key->priv.size);
done_reading += sizeof(key->priv.size);
if (bufferSz < done_reading + key->priv.size) {
#ifdef DEBUG_WOLFTPM
printf("Buffer size check failed (%d)\n", bufferSz);
#endif
return BUFFER_E;
}
XMEMCPY(key->priv.buffer, runner, key->priv.size);
done_reading += key->priv.size;
if (done_reading != bufferSz) {
#ifdef DEBUG_WOLFTPM
printf("Extra data left in buffer (%d!=%d)\n",
bufferSz, (word32)done_reading);
#endif
return BUFFER_E;
}
return TPM_RC_SUCCESS;
}
int wolfTPM2_SetKeyAuthPassword(WOLFTPM2_KEY *key, const byte* auth,
int authSz)
{
if ((key == NULL) || (authSz < 0)) {
return BAD_FUNC_ARG;
}
if ( ((auth != NULL) && (authSz == 0))
|| ((auth == NULL) && (authSz != 0))
) {
return BAD_FUNC_ARG;
}
/* specify auth password for storage key */
key->handle.auth.size = authSz;
if (auth != NULL) {
XMEMCPY(key->handle.auth.buffer, auth, authSz);
}
return TPM_RC_SUCCESS;
}
/* Access already started TPM module */
int wolfTPM2_OpenExisting(WOLFTPM2_DEV* dev, TPM2HalIoCb ioCb, void* userCtx)
{
int rc;
if (dev == NULL) {
return BAD_FUNC_ARG;
}
XMEMSET(dev, 0, sizeof(WOLFTPM2_DEV));
/* The 0 startup indicates use existing locality */
rc = wolfTPM2_Init_ex(&dev->ctx, ioCb, userCtx, 0);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_Init failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
#endif
return rc;
}
/* define the default session auth */
XMEMSET(dev->session, 0, sizeof(dev->session));
wolfTPM2_SetAuthPassword(dev, 0, NULL);
return rc;
}
int wolfTPM2_GetTpmDevId(WOLFTPM2_DEV* dev)
{
if (dev == NULL) {
return BAD_FUNC_ARG;
}
return (int)dev->ctx.did_vid; /* return something besides INVALID_DEVID */
}
int wolfTPM2_SelfTest(WOLFTPM2_DEV* dev)
{
int rc;
SelfTest_In selfTest;
if (dev == NULL)
return BAD_FUNC_ARG;
/* Full self test */
XMEMSET(&selfTest, 0, sizeof(selfTest));
selfTest.fullTest = YES;
rc = TPM2_SelfTest(&selfTest);
#ifdef WOLFTPM_WINAPI
if (rc == (int)TPM_E_COMMAND_BLOCKED) { /* 0x80280400 */
#ifdef DEBUG_WOLFTPM
printf("TPM2_SelfTest not allowed on Windows TBS (err 0x%x)\n", rc);
#endif
rc = TPM_RC_SUCCESS; /* report success */
}
#endif
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_SelfTest failed 0x%x: %s\n", rc, TPM2_GetRCString(rc));
#endif
return rc;
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_SelfTest pass\n");
#endif
return rc;
}
/* Infineon SLB9670
* TPM_PT_MANUFACTURER "IFX"
* TPM_PT_VENDOR_STRING_1 "SLB9"
* TPM_PT_VENDOR_STRING_2 "670 "
* TPM_PT_FIRMWARE_VERSION_1 0x00070055 = v7.85
* TPM_PT_FIRMWARE_VERSION_2 0x0011CB02
* Byte 1: reserved.
* Bytes 2-3: build num = 11CB,
* Byte 4: 0x00 (TPM CC), 0x02 (no CC)
* TPM_PT_MODES = Bit 0 = FIPS_140_2
*/
/* ST33TP
* TPM_PT_MANUFACTURER 0x53544D20: "STM"
* TPM_PT_FIRMWARE_VERSION_1 TPM FW version: 0x00006400
* TPM_PT_VENDOR_TPM_TYPE 1: TPM 2.0
* TPM_PT_MODES: BIT 0 SET (1): indicates that the TPM is designed to
* comply with all of the FIPS 140-2 requirements at Level 1 or higher.
* TPM_PT_FIRMWARE_VERSION_2: ST Internal Additional Version
*/
static int wolfTPM2_ParseCapabilities(WOLFTPM2_CAPS* caps,
TPML_TAGGED_TPM_PROPERTY* props)
{
int rc = 0;
word32 i, val, len;
for (i=0; i<props->count && i<MAX_TPM_PROPERTIES; i++) {
val = props->tpmProperty[i].value;
switch (props->tpmProperty[i].property) {
case TPM_PT_MANUFACTURER:
val = TPM2_Packet_SwapU32(val); /* swap for little endian */
XMEMCPY(&caps->mfgStr, &val, sizeof(UINT32));
if (XMEMCMP(&caps->mfgStr, "IFX", 3) == 0) {
caps->mfg = TPM_MFG_INFINEON;
}
else if (XMEMCMP(&caps->mfgStr, "STM", 3) == 0) {
caps->mfg = TPM_MFG_STM;
caps->req_wait_state = 1;
}
else if (XMEMCMP(&caps->mfgStr, "MCHP", 4) == 0) {
caps->mfg = TPM_MFG_MCHP;
caps->req_wait_state = 1;
}
else if (XMEMCMP(&caps->mfgStr, "NTC", 4) == 0) {
caps->mfg = TPM_MFG_NUVOTON;
caps->req_wait_state = 1;
}
else if (XMEMCMP(&caps->mfgStr, "NTZ", 4) == 0) {
caps->mfg = TPM_MFG_NATIONTECH;
caps->req_wait_state = 1;
}
break;
case TPM_PT_VENDOR_STRING_1:
case TPM_PT_VENDOR_STRING_2:
case TPM_PT_VENDOR_STRING_3:
case TPM_PT_VENDOR_STRING_4:
val = TPM2_Packet_SwapU32(val); /* swap for little endian */
len = (word32)XSTRLEN(caps->vendorStr); /* add to existing string */
if (len + sizeof(UINT32) < sizeof(caps->vendorStr)) {
XMEMCPY(&caps->vendorStr[len], &val, sizeof(UINT32));
}
if (val == 0x46495053) { /* FIPS */
caps->fips140_2 = 1;
}
break;
case TPM_PT_VENDOR_TPM_TYPE:
caps->tpmType = val;
break;
case TPM_PT_FIRMWARE_VERSION_1:
caps->fwVerMajor = val >> 16;
caps->fwVerMinor = val & 0xFFFF;
break;
case TPM_PT_FIRMWARE_VERSION_2:
if (caps->mfg == TPM_MFG_INFINEON) {
caps->fwVerVendor = val >> 8;
caps->cc_eal4 = (val & 0x00000002) ? 0 : 1;
}
else {
caps->fwVerVendor = val;
}
break;
case TPM_PT_MODES:
caps->fips140_2 = (val & 0x00000001) ? 1: 0;
break;
default:
break;
}
}
return rc;
}
static int wolfTPM2_GetCapabilities_NoDev(WOLFTPM2_CAPS* cap)
{
int rc;
GetCapability_In in;
GetCapability_Out out;
if (cap == NULL)
return BAD_FUNC_ARG;
/* clear caps */
XMEMSET(cap, 0, sizeof(WOLFTPM2_CAPS));
/* Get Capabilities TPM_PT_MANUFACTURER thru TPM_PT_FIRMWARE_VERSION_2 */
XMEMSET(&in, 0, sizeof(in));
in.capability = TPM_CAP_TPM_PROPERTIES;
in.property = TPM_PT_MANUFACTURER;
in.propertyCount = 8;
rc = TPM2_GetCapability(&in, &out);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_GetCapability failed 0x%x: %s\n", rc,
TPM2_GetRCString(rc));
#endif
return rc;
}
rc = wolfTPM2_ParseCapabilities(cap, &out.capabilityData.data.tpmProperties);
if (rc != 0)
return rc;
/* Get Capability TPM_PT_MODES */
XMEMSET(&in, 0, sizeof(in));
in.capability = TPM_CAP_TPM_PROPERTIES;
in.property = TPM_PT_MODES;
in.propertyCount = 1;
rc = TPM2_GetCapability(&in, &out);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_GetCapability failed 0x%x: %s\n", rc,
TPM2_GetRCString(rc));
#endif
return rc;
}
rc = wolfTPM2_ParseCapabilities(cap, &out.capabilityData.data.tpmProperties);
return rc;
}
int wolfTPM2_GetCapabilities(WOLFTPM2_DEV* dev, WOLFTPM2_CAPS* cap)
{
if (dev == NULL)
return BAD_FUNC_ARG;
return wolfTPM2_GetCapabilities_NoDev(cap);
}
int wolfTPM2_UnsetAuth(WOLFTPM2_DEV* dev, int index)
{
TPM2_AUTH_SESSION* session;
if (dev == NULL || index >= MAX_SESSION_NUM || index < 0) {
return BAD_FUNC_ARG;
}
session = &dev->session[index];
XMEMSET(session, 0, sizeof(TPM2_AUTH_SESSION));
return TPM2_SetSessionAuth(dev->session);
}
int wolfTPM2_UnsetAuthSession(WOLFTPM2_DEV* dev, int index,
WOLFTPM2_SESSION* tpmSession)
{
TPM2_AUTH_SESSION* devSession;
if (dev == NULL || tpmSession == NULL ||
index >= MAX_SESSION_NUM || index < 0) {
return BAD_FUNC_ARG;
}
devSession = &dev->session[index];
/* save off nonce from TPM to support continued use of session */
XMEMCPY(&tpmSession->nonceTPM, &devSession->nonceTPM, sizeof(TPM2B_NONCE));
XMEMSET(devSession, 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)
{
TPM2_AUTH_SESSION* session;
if (dev == NULL || index >= MAX_SESSION_NUM || index < 0) {
return BAD_FUNC_ARG;
}
session = &dev->session[index];
XMEMSET(session, 0, sizeof(TPM2_AUTH_SESSION));
session->sessionHandle = sessionHandle;
session->sessionAttributes = sessionAttributes;
if (auth) {
session->auth.size = auth->size;
XMEMCPY(session->auth.buffer, auth->buffer, auth->size);
}
if (name) {
session->name.size = name->size;
XMEMCPY(session->name.name, name->name, name->size);
}
TPM2_SetSessionAuth(dev->session);
return TPM_RC_SUCCESS;
}
int wolfTPM2_SetAuthPassword(WOLFTPM2_DEV* dev, int index,
const TPM2B_AUTH* auth)
{
return wolfTPM2_SetAuth(dev, index, TPM_RS_PW, auth, 0, NULL);
}
int wolfTPM2_SetAuthHandle(WOLFTPM2_DEV* dev, int index,
const WOLFTPM2_HANDLE* handle)
{
const TPM2B_AUTH* auth = NULL;
const TPM2B_NAME* name = NULL;
if (dev == NULL || index >= MAX_SESSION_NUM) {
return BAD_FUNC_ARG;
}
if (handle) {
/* don't set auth for policy session, just name */
if (handle->policyAuth) {
TPM2_AUTH_SESSION* session = &dev->session[index];
session->name.size = handle->name.size;
XMEMCPY(session->name.name, handle->name.name, handle->name.size);
return TPM_RC_SUCCESS;
}
auth = &handle->auth;
name = &handle->name;
}
return wolfTPM2_SetAuth(dev, index, TPM_RS_PW, auth, 0, name);
}
int wolfTPM2_SetAuthHandleName(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];
if (session->auth.size == 0 && handle->auth.size > 0) {
session->auth.size = handle->auth.size;
XMEMCPY(session->auth.buffer, handle->auth.buffer, handle->auth.size);
}
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,
WOLFTPM2_SESSION* tpmSession, TPMA_SESSION sessionAttributes)
{
int rc;
if (dev == NULL || index >= MAX_SESSION_NUM) {
return BAD_FUNC_ARG;
}
if (tpmSession == NULL) {
/* clearing auth session */
XMEMSET(&dev->session[index], 0, sizeof(TPM2_AUTH_SESSION));
return TPM_RC_SUCCESS;
}
rc = wolfTPM2_SetAuth(dev, index, tpmSession->handle.hndl,
&tpmSession->handle.auth, sessionAttributes, NULL);
if (rc == TPM_RC_SUCCESS) {
TPM2_AUTH_SESSION* session = &dev->session[index];
/* save off session attributes */
tpmSession->sessionAttributes = sessionAttributes;
/* define the symmetric algorithm */
session->authHash = tpmSession->authHash;
XMEMCPY(&session->symmetric, &tpmSession->handle.symmetric,
sizeof(TPMT_SYM_DEF));
/* fresh nonce generated in TPM2_CommandProcess based on this size */
session->nonceCaller.size = TPM2_GetHashDigestSize(WOLFTPM2_WRAP_DIGEST);
/* Capture TPM provided nonce */
session->nonceTPM.size = tpmSession->nonceTPM.size;
XMEMCPY(session->nonceTPM.buffer, tpmSession->nonceTPM.buffer,
session->nonceTPM.size);
/* Parameter Encryption or Policy 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)))
|| TPM2_IS_POLICY_SESSION(session->sessionHandle))
{
session->auth.size = TPM2_GetHashDigestSize(session->authHash);
}
}
return rc;
}
int wolfTPM2_CreateAuthSession_EkPolicy(WOLFTPM2_DEV* dev,
WOLFTPM2_SESSION* tpmSession)
{
int rc = TPM_RC_FAILURE;
PolicySecret_In policySecretIn;
PolicySecret_Out policySecretOut;
/* Endorsement Key requires authorization with Policy */
rc = wolfTPM2_StartSession(dev, tpmSession, NULL, NULL,
TPM_SE_POLICY, TPM_ALG_NULL);
if (rc == TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_StartAuthSession: sessionHandle 0x%x\n",
(word32)tpmSession->handle.hndl);
#endif
/* Provide Endorsement Auth using PolicySecret */
XMEMSET(&policySecretIn, 0, sizeof(policySecretIn));
policySecretIn.authHandle = TPM_RH_ENDORSEMENT;
policySecretIn.policySession = tpmSession->handle.hndl;
rc = TPM2_PolicySecret(&policySecretIn, &policySecretOut);
#ifdef DEBUG_WOLFTPM
if (rc == TPM_RC_SUCCESS) {
printf("policySecret applied on session\n");
}
#endif
}
return rc;
}
int wolfTPM2_Cleanup_ex(WOLFTPM2_DEV* dev, int doShutdown)
{
int rc = 0;
if (dev == NULL) {
return BAD_FUNC_ARG;
}
#ifdef WOLFTPM_CRYPTOCB
/* make sure crypto dev callback is unregistered */
rc = wolfTPM2_ClearCryptoDevCb(dev, INVALID_DEVID);
if (rc != 0)
return rc;
#endif
if (doShutdown) {
Shutdown_In shutdownIn;
XMEMSET(&shutdownIn, 0, sizeof(shutdownIn));
shutdownIn.shutdownType = TPM_SU_CLEAR;
rc = TPM2_Shutdown(&shutdownIn);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_Shutdown failed %d: %s\n",
rc, wolfTPM2_GetRCString(rc));
#endif
/* finish cleanup and return error */
}
}
TPM2_Cleanup(&dev->ctx);
return rc;
}
int wolfTPM2_Cleanup(WOLFTPM2_DEV* dev)
{
#if defined(WOLFTPM_WINAPI)
return wolfTPM2_Cleanup_ex(dev, 0);
#else
return wolfTPM2_Cleanup_ex(dev, 1);
#endif
}
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) && \
!defined(WC_NO_RNG) && defined(WOLFSSL_PUBLIC_MP)
/* The KDF for producing a symmetric key.
* See TPM 2.0 Part 1 specification (11.4.9.3)
*/
static int TPM2_KDFe(
TPM_ALG_ID hashAlg, /* IN: hash algorithm used */
const TPM2B_DATA *Z, /* IN: x coordinate of shared secret */
const char *label, /* IN: a 0-byte terminated label used in KDF */
const TPM2B_DATA *partyUInfo, /* IN: x coordinate of our public key */
const TPM2B_DATA *partyVInfo, /* IN: x coordinate of peer's public key */
BYTE *key, /* OUT: key buffer */
UINT32 keySz /* IN: size of generated key in bytes */
)
{
int ret;
enum wc_HashType hashType;
wc_HashAlg hash_ctx;
word32 counter = 0;
int hLen, copyLen, lLen = 0;
byte uint32Buf[sizeof(UINT32)];
UINT32 pos;
BYTE* keyStream = key;
byte hash[WC_MAX_DIGEST_SIZE];
if (key == NULL || Z == NULL)
return BAD_FUNC_ARG;
ret = TPM2_GetHashType(hashAlg);
if (ret == WC_HASH_TYPE_NONE)
return NOT_COMPILED_IN;
hashType = (enum wc_HashType)ret;
hLen = TPM2_GetHashDigestSize(hashAlg);
if ((hLen <= 0) || (hLen > WC_MAX_DIGEST_SIZE))
return NOT_COMPILED_IN;
/* get label length if provided, including null termination */
if (label != NULL) {
lLen = (int)XSTRLEN(label) + 1;
}
ret = wc_HashInit(&hash_ctx, hashType);
if (ret != 0)
return ret;
/* generate required bytes - blocks sized digest */
for (pos = 0; pos < keySz; pos += hLen) {
/* KDFe counter starts at 1 */
counter++;
copyLen = hLen;
/* add counter */
TPM2_Packet_U32ToByteArray(counter, uint32Buf);
ret = wc_HashUpdate(&hash_ctx, hashType, uint32Buf,
(word32)sizeof(uint32Buf));
/* add Z */
if (ret == 0) {
ret = wc_HashUpdate(&hash_ctx, hashType, Z->buffer, Z->size);
}
/* add label */
if (ret == 0 && label != NULL) {
ret = wc_HashUpdate(&hash_ctx, hashType, (byte*)label, lLen);
}
/* add partyUInfo */
if (ret == 0 && partyUInfo != NULL && partyUInfo->size > 0) {
ret = wc_HashUpdate(&hash_ctx, hashType, partyUInfo->buffer,
partyUInfo->size);
}
/* add partyVInfo */
if (ret == 0 && partyVInfo != NULL && partyVInfo->size > 0) {
ret = wc_HashUpdate(&hash_ctx, hashType, partyVInfo->buffer,
partyVInfo->size);
}
/* get result */
if (ret == 0) {
ret = wc_HashFinal(&hash_ctx, hashType, hash);
}
if (ret != 0) {
goto exit;
}
if ((UINT32)hLen > keySz - pos) {
copyLen = keySz - pos;
}
XMEMCPY(keyStream, hash, copyLen);
keyStream += copyLen;
}
ret = keySz;
exit:
wc_HashFree(&hash_ctx, hashType);
/* return length rounded up to nearest 8 multiple */
return ret;
}
#ifdef ALT_ECC_SIZE
#error use of ecc_point below does not support ALT_ECC_SIZE
#endif
/* returns both the plaintext and encrypted value */
/* ECC: data = derived symmetric key
* secret = exported public point */
static int wolfTPM2_EncryptSecret_ECC(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* tpmKey,
TPM2B_DATA *data, TPM2B_ENCRYPTED_SECRET *secret,
const char* label)
{
int rc;
WC_RNG rng;
ecc_key eccKeyPriv, eccKeyPub;
const TPMT_PUBLIC *publicArea;
TPM2B_ECC_POINT pubPoint, secretPoint;
ecc_point r[1];
mp_int prime, a;
word32 keySz;
publicArea = &tpmKey->pub.publicArea;
XMEMSET(&rng, 0, sizeof(rng));
XMEMSET(&eccKeyPub, 0, sizeof(eccKeyPub));
XMEMSET(&eccKeyPriv, 0, sizeof(eccKeyPriv));
XMEMSET(&pubPoint, 0, sizeof(pubPoint));
XMEMSET(&secretPoint, 0, sizeof(secretPoint));
XMEMSET(r, 0, sizeof(r));
XMEMSET(&prime, 0, sizeof(prime));
XMEMSET(&a, 0, sizeof(a));
rc = wc_InitRng_ex(&rng, NULL, INVALID_DEVID);
if (rc == 0) {
rc = wc_ecc_init_ex(&eccKeyPub, NULL, INVALID_DEVID);
}
if (rc == 0) {
rc = wc_ecc_init_ex(&eccKeyPriv, NULL, INVALID_DEVID);
}
#ifdef ECC_TIMING_RESISTANT
if (rc == 0) {
wc_ecc_set_rng(&eccKeyPriv, &rng);
wc_ecc_set_rng(&eccKeyPub, &rng);
}
#endif
if (rc == 0) {
/* import peer public key */
rc = wolfTPM2_EccKey_TpmToWolf(dev, (WOLFTPM2_KEY*)tpmKey, &eccKeyPub);
}
if (rc == 0) {
/* create local private key */
rc = wc_ecc_make_key_ex(&rng, 0, &eccKeyPriv,
TPM2_GetWolfCurve(publicArea->parameters.eccDetail.curveID));
}
if (rc == 0) {
keySz = wc_ecc_size(&eccKeyPriv);
/* export private's public point as data */
rc = wolfTPM2_EccKey_WolfToPubPoint(dev, &eccKeyPriv, &pubPoint);
}
if (rc == 0) {
/* Export public point x/y into secret buffer for peer */
TPM2_Packet packet;
XMEMSET(&packet, 0, sizeof(packet));
packet.buf = secret->secret;
packet.size = sizeof(secret->secret);
TPM2_Packet_AppendEccPoint(&packet, &pubPoint.point);
secret->size = packet.pos;
}
if (rc == 0) {
rc = mp_init_multi(&prime, &a, r->x, r->y, r->z, NULL);
}
if (rc == 0) {
rc = mp_read_radix(&prime, eccKeyPriv.dp->prime, MP_RADIX_HEX);
}
if (rc == 0) {
rc = mp_read_radix(&a, eccKeyPriv.dp->Af, MP_RADIX_HEX);
}
if (rc == 0) {
/* perform point multiply */
rc = wc_ecc_mulmod(wc_ecc_key_get_priv(&eccKeyPriv), &eccKeyPub.pubkey,
r, &a, &prime, 1);
}
if (rc == 0) {
/* export shared secret x - zero pad to key size */
secretPoint.point.x.size = mp_unsigned_bin_size(r->x);
rc = mp_to_unsigned_bin(r->x,
&secretPoint.point.x.buffer[keySz-secretPoint.point.x.size]);
secretPoint.point.x.size = keySz;
}
if (rc == 0) {
/* set size encryption key */
data->size = TPM2_GetHashDigestSize(publicArea->nameAlg);
rc = TPM2_KDFe(
publicArea->nameAlg,
(const TPM2B_DATA*)&secretPoint.point.x,
label,
(const TPM2B_DATA*)&pubPoint.point.x,
(const TPM2B_DATA*)&publicArea->unique.ecc.x,
data->buffer,
data->size
);
}
mp_clear(r->x);
mp_clear(r->y);
mp_clear(r->z);
mp_clear(&a);
mp_clear(&prime);
wc_ecc_free(&eccKeyPub);
wc_ecc_free(&eccKeyPriv);
wc_FreeRng(&rng);
if (rc >= 0) {
rc = (rc == data->size) ? 0 /* success */ : BUFFER_E /* fail */;
}
return rc;
}
#endif /* !WOLFTPM2_NO_WOLFCRYPT && HAVE_ECC && !WC_NO_RNG */
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && !defined(NO_RSA) && !defined(WC_NO_RNG)
/* returns both the plaintext and encrypted value */
/* RSA: data = input to encrypt or generated random value
* secret = RSA encrypted random */
static int wolfTPM2_EncryptSecret_RSA(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* tpmKey,
TPM2B_DATA *data, TPM2B_ENCRYPTED_SECRET *secret, const char* label)
{
int rc, mgf;
enum wc_HashType hashType;
WC_RNG rng;
RsaKey rsaKey;
const TPMT_PUBLIC *publicArea;
publicArea = &tpmKey->pub.publicArea;
if (publicArea->nameAlg == TPM_ALG_SHA1) {
hashType = WC_HASH_TYPE_SHA;
mgf = WC_MGF1SHA1;
}
else if (publicArea->nameAlg == TPM_ALG_SHA256) {
hashType = WC_HASH_TYPE_SHA256;
mgf = WC_MGF1SHA256;
}
else {
return NOT_COMPILED_IN;
}
XMEMSET(&rng, 0, sizeof(rng));
XMEMSET(&rsaKey, 0, sizeof(rsaKey));
rc = wc_InitRng_ex(&rng, NULL, INVALID_DEVID);
if (rc == 0) {
rc = wc_InitRsaKey_ex(&rsaKey, NULL, INVALID_DEVID);
}
#ifdef WC_RSA_BLINDING
if (rc == 0) {
wc_RsaSetRNG(&rsaKey, &rng);
}
#endif
if (rc == 0 && data->size == 0) {
/* Generate random value to exchange for encryption */
data->size = TPM2_GetHashDigestSize(publicArea->nameAlg);
rc = wc_RNG_GenerateBlock(&rng, data->buffer, data->size);
}
if (rc == 0) {
rc = wolfTPM2_RsaKey_TpmToWolf(dev, (WOLFTPM2_KEY*)tpmKey, &rsaKey);
}
if (rc == 0) {
secret->size = publicArea->unique.rsa.size;
rc = wc_RsaPublicEncrypt_ex(
data->buffer, /* in pointer to the buffer for encryption */
data->size, /* inLen length of in parameter */
secret->secret, /* out encrypted msg created */
secret->size, /* outLen length of buffer available to hold encrypted msg */
&rsaKey, /* key initialized RSA key struct */
&rng, /* rng initialized WC_RNG struct */
WC_RSA_OAEP_PAD, /* type type of padding to use (WC_RSA_OAEP_PAD or WC_RSA_PKCSV15_PAD) */
hashType, /* hash type of hash to use (choices can be found in hash.h) */
mgf, /* mgf type of mask generation function to use */
(byte*)label, /* label an optional label to associate with encrypted message */
(word32)XSTRLEN(label)+1 /* labelSz size of the optional label used */
);
}
wc_FreeRsaKey(&rsaKey);
wc_FreeRng(&rng);
if (rc > 0) {
rc = (rc == secret->size) ? 0 /* success */ : BUFFER_E /* fail */;
}
return rc;
}
#endif /* !WOLFTPM2_NO_WOLFCRYPT && !NO_RSA && !WC_NO_RNG */
int wolfTPM2_EncryptSecret(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* tpmKey,
TPM2B_DATA *data, TPM2B_ENCRYPTED_SECRET *secret,
const char* label)
{
int rc = NOT_COMPILED_IN;
/* if a tpmKey is not present then we are using an unsalted session */
if (dev == NULL || tpmKey == NULL || data == NULL || secret == NULL) {
return TPM_RC_SUCCESS;
}
#ifdef DEBUG_WOLFTPM
printf("Encrypt secret: Alg %s, Label %s\n",
TPM2_GetAlgName(tpmKey->pub.publicArea.type), label);
#endif
#ifndef WOLFTPM2_NO_WOLFCRYPT
switch (tpmKey->pub.publicArea.type) {
#if defined(HAVE_ECC) && !defined(WC_NO_RNG) && defined(WOLFSSL_PUBLIC_MP)
case TPM_ALG_ECC:
rc = wolfTPM2_EncryptSecret_ECC(dev, tpmKey, data, secret, label);
break;
#endif
#if !defined(NO_RSA) && !defined(WC_NO_RNG)
case TPM_ALG_RSA:
rc = wolfTPM2_EncryptSecret_RSA(dev, tpmKey, data, secret, label);
break;
#endif
default:
rc = NOT_COMPILED_IN;
break;
}
#ifdef WOLFTPM_DEBUG_VERBOSE
printf("Encrypt Secret %d: %d bytes\n", rc, data->size);
TPM2_PrintBin(data->buffer, data->size);
#endif
#endif /* !WOLFTPM2_NO_WOLFCRYPT */
(void)label;
return rc;
}
int wolfTPM2_StartSession(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* session,
WOLFTPM2_KEY* tpmKey, WOLFTPM2_HANDLE* bind, TPM_SE sesType,
int encDecAlg)
{
int rc;
StartAuthSession_In authSesIn;
StartAuthSession_Out authSesOut;
TPM2B_AUTH* bindAuth = NULL;
TPM2B_DATA keyIn;
TPMI_ALG_HASH authHash = WOLFTPM2_WRAP_DIGEST;
int hashDigestSz;
if (dev == NULL || session == NULL)
return BAD_FUNC_ARG;
XMEMSET(session, 0, sizeof(WOLFTPM2_SESSION));
XMEMSET(&authSesIn, 0, sizeof(authSesIn));
authSesIn.authHash = authHash;
hashDigestSz = TPM2_GetHashDigestSize(authHash);
if (hashDigestSz <= 0) {
return NOT_COMPILED_IN;
}
/* set session auth for key */
if (tpmKey) {
TPMA_SESSION sessionAttributes = 0;
if (encDecAlg == TPM_ALG_CFB || encDecAlg == TPM_ALG_XOR) {
/* if parameter encryption is enabled and key bind set, enable
* encrypt/decrypt by default */
sessionAttributes |= (TPMA_SESSION_decrypt | TPMA_SESSION_encrypt);
}
wolfTPM2_SetAuth(dev, 0, tpmKey->handle.hndl, &tpmKey->handle.auth,
sessionAttributes, NULL);
authSesIn.tpmKey = tpmKey->handle.hndl;
}
else {
wolfTPM2_SetAuthPassword(dev, 0, NULL);
authSesIn.tpmKey = (TPMI_DH_OBJECT)TPM_RH_NULL;
}
/* setup bind key */
authSesIn.bind = (TPMI_DH_ENTITY)TPM_RH_NULL;
if (bind) {
authSesIn.bind = bind->hndl;
bindAuth = &bind->auth;
}
authSesIn.sessionType = sesType;
if (encDecAlg == TPM_ALG_CFB) {
authSesIn.symmetric.algorithm = TPM_ALG_AES;
authSesIn.symmetric.keyBits.aes = 128;
authSesIn.symmetric.mode.aes = TPM_ALG_CFB;
}
else if (encDecAlg == TPM_ALG_XOR) {
authSesIn.symmetric.algorithm = TPM_ALG_XOR;
authSesIn.symmetric.keyBits.xorr = TPM_ALG_SHA256;
authSesIn.symmetric.mode.sym = TPM_ALG_NULL;
}
else {
authSesIn.symmetric.algorithm = TPM_ALG_NULL;
}
authSesIn.nonceCaller.size = hashDigestSz;
rc = TPM2_GetNonce(authSesIn.nonceCaller.buffer,
authSesIn.nonceCaller.size);
if (rc < 0) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_GetNonce failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
#endif
return rc;
}
if (authSesIn.tpmKey != TPM_RH_NULL) {
/* Generate random salt */
session->salt.size = hashDigestSz;
rc = TPM2_GetNonce(session->salt.buffer, session->salt.size);
if (rc != 0) {
return rc;
}
/* Encrypt salt using "SECRET" */
rc = wolfTPM2_EncryptSecret(dev, tpmKey, (TPM2B_DATA*)&session->salt,
&authSesIn.encryptedSalt, "SECRET");
if (rc != 0) {
#ifdef DEBUG_WOLFTPM
printf("Building encrypted salt failed %d: %s!\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
}
rc = TPM2_StartAuthSession(&authSesIn, &authSesOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_StartAuthSession failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
/* Calculate "key" and store into auth */
/* key is bindAuthValue || salt */
XMEMSET(&keyIn, 0, sizeof(keyIn));
if (bindAuth && bindAuth->size > 0) {
XMEMCPY(&keyIn.buffer[keyIn.size], bindAuth->buffer, bindAuth->size);
keyIn.size += bindAuth->size;
}
if (session->salt.size > 0) {
XMEMCPY(&keyIn.buffer[keyIn.size], session->salt.buffer,
session->salt.size);
keyIn.size += session->salt.size;
}
if (keyIn.size > 0) {
session->handle.auth.size = hashDigestSz;
rc = TPM2_KDFa(authSesIn.authHash, &keyIn, "ATH",
&authSesOut.nonceTPM, &authSesIn.nonceCaller,
session->handle.auth.buffer, session->handle.auth.size);
if (rc != hashDigestSz) {
#ifdef DEBUG_WOLFTPM
printf("KDFa ATH Gen Error %d\n", rc);
#endif
return TPM_RC_FAILURE;
}
rc = TPM_RC_SUCCESS;
}
#ifdef WOLFTPM_DEBUG_VERBOSE
printf("Session Key %d\n", session->handle.auth.size);
TPM2_PrintBin(session->handle.auth.buffer, session->handle.auth.size);
#endif
/* return session */
session->type = authSesIn.sessionType;
session->authHash = authSesIn.authHash;
session->handle.hndl = authSesOut.sessionHandle;
wolfTPM2_CopySymmetric(&session->handle.symmetric, &authSesIn.symmetric);
if (bind) {
wolfTPM2_CopyName(&session->handle.name, &bind->name);
}
session->nonceCaller.size = authSesIn.nonceCaller.size;
if (session->nonceCaller.size > (UINT16)sizeof(session->nonceCaller.buffer))
session->nonceCaller.size = (UINT16)sizeof(session->nonceCaller.buffer);
XMEMCPY(session->nonceCaller.buffer, authSesIn.nonceCaller.buffer,
authSesIn.nonceCaller.size);
session->nonceTPM.size = authSesOut.nonceTPM.size;
if (session->nonceTPM.size > (UINT16)sizeof(session->nonceTPM.buffer))
session->nonceTPM.size = (UINT16)sizeof(session->nonceTPM.buffer);
XMEMCPY(session->nonceTPM.buffer, authSesOut.nonceTPM.buffer,
session->nonceTPM.size);
#ifdef DEBUG_WOLFTPM
printf("TPM2_StartAuthSession: handle 0x%x, algorithm %s\n",
(word32)session->handle.hndl,
TPM2_GetAlgName(authSesIn.symmetric.algorithm));
#endif
return rc;
}
int wolfTPM2_CreatePrimaryKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
TPM_HANDLE primaryHandle, TPMT_PUBLIC* publicTemplate,
const byte* auth, int authSz)
{
int rc;
CreatePrimary_In createPriIn;
CreatePrimary_Out createPriOut;
if (dev == NULL || key == NULL || publicTemplate == NULL)
return BAD_FUNC_ARG;
/* set session auth to blank */
wolfTPM2_SetAuthPassword(dev, 0, NULL);
/* clear output key buffer */
XMEMSET(key, 0, sizeof(WOLFTPM2_KEY));
/* setup create primary command */
XMEMSET(&createPriIn, 0, sizeof(createPriIn));
/* TPM_RH_OWNER, TPM_RH_ENDORSEMENT, TPM_RH_PLATFORM or TPM_RH_NULL */
createPriIn.primaryHandle = primaryHandle;
if (auth && authSz > 0) {
int nameAlgDigestSz = TPM2_GetHashDigestSize(publicTemplate->nameAlg);
/* truncate if longer than name size */
if (nameAlgDigestSz > 0 && authSz > nameAlgDigestSz)
authSz = nameAlgDigestSz;
XMEMCPY(createPriIn.inSensitive.sensitive.userAuth.buffer, auth, authSz);
/* make sure auth is same size as nameAlg digest size */
if (nameAlgDigestSz > 0 && authSz < nameAlgDigestSz)
authSz = nameAlgDigestSz;
createPriIn.inSensitive.sensitive.userAuth.size = authSz;
}
XMEMCPY(&createPriIn.inPublic.publicArea, publicTemplate,
sizeof(TPMT_PUBLIC));
rc = TPM2_CreatePrimary(&createPriIn, &createPriOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_CreatePrimary: failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
key->handle.hndl = createPriOut.objectHandle;
wolfTPM2_CopyAuth(&key->handle.auth,
&createPriIn.inSensitive.sensitive.userAuth);
wolfTPM2_CopyName(&key->handle.name, &createPriOut.name);
wolfTPM2_CopySymmetric(&key->handle.symmetric,
&createPriOut.outPublic.publicArea.parameters.asymDetail.symmetric);
wolfTPM2_CopyPub(&key->pub, &createPriOut.outPublic);
#ifdef DEBUG_WOLFTPM
printf("TPM2_CreatePrimary: 0x%x (%d bytes)\n",
(word32)key->handle.hndl, key->pub.size);
#endif
return rc;
}
int wolfTPM2_ChangeAuthKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
WOLFTPM2_HANDLE* parent, const byte* auth, int authSz)
{
int rc;
ObjectChangeAuth_In changeIn;
ObjectChangeAuth_Out changeOut;
Load_In loadIn;
Load_Out loadOut;
if (dev == NULL || key == NULL || parent == NULL)
return BAD_FUNC_ARG;
/* set session auth for key */
wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
XMEMSET(&changeIn, 0, sizeof(changeIn));
changeIn.objectHandle = key->handle.hndl;
changeIn.parentHandle = parent->hndl;
if (auth) {
if (authSz > (int)sizeof(changeIn.newAuth.buffer))
authSz = (int)sizeof(changeIn.newAuth.buffer);
changeIn.newAuth.size = authSz;
XMEMCPY(changeIn.newAuth.buffer, auth, changeIn.newAuth.size);
}
rc = TPM2_ObjectChangeAuth(&changeIn, &changeOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_ObjectChangeAuth failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
/* unload old key */
wolfTPM2_UnloadHandle(dev, &key->handle);
/* set session auth for parent key */
wolfTPM2_SetAuthHandle(dev, 0, parent);
/* Load new key */
XMEMSET(&loadIn, 0, sizeof(loadIn));
loadIn.parentHandle = parent->hndl;
wolfTPM2_CopyPriv(&loadIn.inPrivate, &changeOut.outPrivate);
wolfTPM2_CopyPub(&loadIn.inPublic, &key->pub);
rc = TPM2_Load(&loadIn, &loadOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_Load key failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
#endif
return rc;
}
key->handle.hndl = loadOut.objectHandle;
wolfTPM2_CopyAuth(&key->handle.auth, &changeIn.newAuth);
wolfTPM2_CopyName(&key->handle.name, &loadOut.name);
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_ChangeAuthKey: Key Handle 0x%x\n",
(word32)key->handle.hndl);
#endif
return rc;
}
int wolfTPM2_CreateKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEYBLOB* keyBlob,
WOLFTPM2_HANDLE* parent, TPMT_PUBLIC* publicTemplate,
const byte* auth, int authSz)
{
int rc;
Create_In createIn;
Create_Out createOut;
if (dev == NULL || keyBlob == NULL || parent == NULL ||
publicTemplate == NULL) {
return BAD_FUNC_ARG;
}
/* clear output key buffer */
XMEMSET(keyBlob, 0, sizeof(WOLFTPM2_KEYBLOB));
XMEMSET(&createOut, 0, sizeof(createOut)); /* make sure pub struct is zero init */
/* set session auth for parent key */
wolfTPM2_SetAuthHandle(dev, 0, parent);
XMEMSET(&createIn, 0, sizeof(createIn));
createIn.parentHandle = parent->hndl;
if (auth) {
createIn.inSensitive.sensitive.userAuth.size = authSz;
XMEMCPY(createIn.inSensitive.sensitive.userAuth.buffer, auth,
createIn.inSensitive.sensitive.userAuth.size);
}
XMEMCPY(&createIn.inPublic.publicArea, publicTemplate, sizeof(TPMT_PUBLIC));
#if 0
/* Optional creation nonce */
createIn.outsideInfo.size = createNoneSz;
XMEMCPY(createIn.outsideInfo.buffer, createNonce, createIn.outsideInfo.size);
#endif
rc = TPM2_Create(&createIn, &createOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_Create key failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
#endif
return rc;
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_Create key: pub %d, priv %d\n",
createOut.outPublic.size, createOut.outPrivate.size);
TPM2_PrintPublicArea(&createOut.outPublic);
#endif
wolfTPM2_CopyAuth(&keyBlob->handle.auth,
&createIn.inSensitive.sensitive.userAuth);
wolfTPM2_CopySymmetric(&keyBlob->handle.symmetric,
&createOut.outPublic.publicArea.parameters.asymDetail.symmetric);
wolfTPM2_CopyPub(&keyBlob->pub, &createOut.outPublic);
wolfTPM2_CopyPriv(&keyBlob->priv, &createOut.outPrivate);
return rc;
}
int wolfTPM2_LoadKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEYBLOB* keyBlob,
WOLFTPM2_HANDLE* parent)
{
int rc;
Load_In loadIn;
Load_Out loadOut;
if (dev == NULL || keyBlob == NULL || parent == NULL)
return BAD_FUNC_ARG;
/* set session auth for parent key */
wolfTPM2_SetAuthHandle(dev, 0, parent);
/* Load new key */
XMEMSET(&loadIn, 0, sizeof(loadIn));
loadIn.parentHandle = parent->hndl;
wolfTPM2_CopyPriv(&loadIn.inPrivate, &keyBlob->priv);
wolfTPM2_CopyPub(&loadIn.inPublic, &keyBlob->pub);
rc = TPM2_Load(&loadIn, &loadOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_Load key failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
#endif
return rc;
}
keyBlob->handle.hndl = loadOut.objectHandle;
wolfTPM2_CopyName(&keyBlob->handle.name, &loadOut.name);
#ifdef DEBUG_WOLFTPM
printf("TPM2_Load Key Handle 0x%x\n", (word32)keyBlob->handle.hndl);
#endif
return rc;
}
int wolfTPM2_CreateAndLoadKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
WOLFTPM2_HANDLE* parent, TPMT_PUBLIC* publicTemplate,
const byte* auth, int authSz)
{
int rc;
WOLFTPM2_KEYBLOB keyBlob;
if (dev == NULL || key == NULL)
return BAD_FUNC_ARG;
rc = wolfTPM2_CreateKey(dev, &keyBlob, parent, publicTemplate, auth, authSz);
if (rc == TPM_RC_SUCCESS) {
rc = wolfTPM2_LoadKey(dev, &keyBlob, parent);
}
/* return loaded key */
XMEMCPY(key, &keyBlob, sizeof(WOLFTPM2_KEY));
return rc;
}
int wolfTPM2_CreateLoadedKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEYBLOB* keyBlob,
WOLFTPM2_HANDLE* parent, TPMT_PUBLIC* publicTemplate,
const byte* auth, int authSz)
{
int rc;
CreateLoaded_In createLoadedIn;
CreateLoaded_Out createLoadedOut;
if (dev == NULL || keyBlob == NULL || parent == NULL || publicTemplate == NULL)
return BAD_FUNC_ARG;
/* clear output key buffer */
XMEMSET(keyBlob, 0, sizeof(WOLFTPM2_KEYBLOB));
XMEMSET(&createLoadedOut, 0, sizeof(createLoadedOut)); /* make sure pub struct is zero init */
/* set session auth for parent key */
wolfTPM2_SetAuthHandle(dev, 0, parent);
XMEMSET(&createLoadedIn, 0, sizeof(createLoadedIn));
createLoadedIn.parentHandle = parent->hndl;
if (auth) {
createLoadedIn.inSensitive.sensitive.userAuth.size = authSz;
XMEMCPY(createLoadedIn.inSensitive.sensitive.userAuth.buffer, auth,
createLoadedIn.inSensitive.sensitive.userAuth.size);
}
XMEMCPY(&createLoadedIn.inPublic.publicArea, publicTemplate, sizeof(TPMT_PUBLIC));
rc = TPM2_CreateLoaded(&createLoadedIn, &createLoadedOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_CreateLoaded key failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
#endif
return rc;
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_CreateLoaded key: pub %d, priv %d\n",
createLoadedOut.outPublic.size, createLoadedOut.outPrivate.size);
TPM2_PrintPublicArea(&createLoadedOut.outPublic);
#endif
keyBlob->handle.hndl = createLoadedOut.objectHandle;
wolfTPM2_CopyAuth(&keyBlob->handle.auth,
&createLoadedIn.inSensitive.sensitive.userAuth);
wolfTPM2_CopySymmetric(&keyBlob->handle.symmetric,
&createLoadedOut.outPublic.publicArea.parameters.asymDetail.symmetric);
wolfTPM2_CopyPub(&keyBlob->pub, &createLoadedOut.outPublic);
wolfTPM2_CopyPriv(&keyBlob->priv, &createLoadedOut.outPrivate);
wolfTPM2_CopyName(&keyBlob->handle.name, &createLoadedOut.name);
return rc;
}
int wolfTPM2_LoadPublicKey_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
const TPM2B_PUBLIC* pub, TPM_HANDLE hierarchy)
{
int rc;
LoadExternal_In loadExtIn;
LoadExternal_Out loadExtOut;
if (dev == NULL || key == NULL || pub == NULL)
return BAD_FUNC_ARG;
/* Loading public key */
XMEMSET(&loadExtIn, 0, sizeof(loadExtIn));
wolfTPM2_CopyPub(&loadExtIn.inPublic, pub);
loadExtIn.hierarchy = hierarchy;
rc = TPM2_LoadExternal(&loadExtIn, &loadExtOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_LoadExternal: failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
key->handle.hndl = loadExtOut.objectHandle;
wolfTPM2_CopySymmetric(&key->handle.symmetric,
&loadExtIn.inPublic.publicArea.parameters.asymDetail.symmetric);
wolfTPM2_CopyName(&key->handle.name, &loadExtOut.name);
wolfTPM2_CopyPub(&key->pub, &loadExtIn.inPublic);
#ifdef DEBUG_WOLFTPM
printf("TPM2_LoadExternal: 0x%x\n", (word32)loadExtOut.objectHandle);
#endif
return rc;
}
int wolfTPM2_LoadPublicKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
const TPM2B_PUBLIC* pub)
{
return wolfTPM2_LoadPublicKey_ex(dev, key, pub, TPM_RH_OWNER);
}
int wolfTPM2_ComputeName(const TPM2B_PUBLIC* pub, TPM2B_NAME* out)
{
int rc;
TPMI_ALG_HASH nameAlg;
#ifndef WOLFTPM2_NO_WOLFCRYPT
TPM2_Packet packet;
TPM2B_TEMPLATE data;
wc_HashAlg hash;
enum wc_HashType hashType;
int hashSz;
#endif
if (pub == NULL || out == NULL)
return BAD_FUNC_ARG;
XMEMSET(out, 0, sizeof(TPM2B_NAME));
nameAlg = pub->publicArea.nameAlg;
if (nameAlg == TPM_ALG_NULL)
return TPM_RC_SUCCESS;
#ifndef WOLFTPM2_NO_WOLFCRYPT
/* Encode public into buffer */
XMEMSET(&packet, 0, sizeof(packet));
packet.buf = data.buffer;
packet.size = sizeof(data.buffer);
TPM2_Packet_AppendPublicArea(&packet, (TPMT_PUBLIC*)&pub->publicArea);
data.size = packet.pos;
/* Hash data - first two bytes are TPM_ALG_ID */
rc = TPM2_GetHashType(nameAlg);
hashType = (enum wc_HashType)rc;
rc = wc_HashGetDigestSize(hashType);
if (rc < 0)
return rc;
hashSz = rc;
/* Encode hash algorithm in first 2 bytes */
nameAlg = TPM2_Packet_SwapU16(nameAlg);
XMEMCPY(&out->name[0], &nameAlg, sizeof(UINT16));
/* Hash of data (name) goes into remainder */
rc = wc_HashInit(&hash, hashType);
if (rc == 0) {
rc = wc_HashUpdate(&hash, hashType, data.buffer, data.size);
if (rc == 0)
rc = wc_HashFinal(&hash, hashType, &out->name[sizeof(UINT16)]);
wc_HashFree(&hash, hashType);
}
/* compute final size */
out->size = hashSz + (int)sizeof(UINT16);
#else
(void)out;
rc = NOT_COMPILED_IN;
#endif
return rc;
}
/* Convert TPM2B_SENSITIVE to TPM2B_PRIVATE */
/* TPM2B_PRIVATE format:
* Integrity (UINT16) + Integrity (HMAC Digest) +
* IV (UINT16) + IV +
* Sensitive
*/
static int SensitiveToPrivate(TPM2B_SENSITIVE* sens, TPM2B_PRIVATE* priv,
TPMI_ALG_HASH nameAlg, TPM2B_NAME* name, const WOLFTPM2_KEY* parentKey,
TPMT_SYM_DEF_OBJECT* sym, TPM2B_DATA* symSeed, int useIv)
{
int rc = 0;
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && \
!defined(NO_AES) && defined(WOLFSSL_AES_CFB) && !defined(NO_HMAC)
int outerWrap = 0, innerWrap = 0;
int digestSz = 0;
int integritySz = 0;
int ivSz = 0;
int sensSz = 0;
BYTE* sensitiveData = NULL;
TPM2B_IV ivField;
TPM2_Packet packet;
TPM2B_SYM_KEY symKey;
TPM2B_DIGEST hmacKey;
Aes enc;
Hmac hmac_ctx;
if (sens == NULL || priv == NULL) {
return BAD_FUNC_ARG;
}
/* if using a parent then use it's integrity algorithm */
if (parentKey != NULL) {
nameAlg = parentKey->pub.publicArea.nameAlg;
symKey.size = parentKey->handle.symmetric.keyBits.sym;
}
else {
symKey.size = sym->keyBits.sym;
}
digestSz = TPM2_GetHashDigestSize(nameAlg);
if (digestSz == 0) {
#ifdef DEBUG_WOLFTPM
printf("SensitiveToPrivate: Invalid name algorithm %d\n", nameAlg);
#endif
return TPM_RC_FAILURE;
}
/* Use outer wrap (Integrity then Encrypt) */
if (symSeed && symSeed->size > 0) {
outerWrap = 1;
integritySz = sizeof(word16) + digestSz;
}
/* Use inner wrap (Encrypt then Integrity) */
if (sym && sym->algorithm != TPM_ALG_NULL) {
innerWrap = 1;
}
/* IV: Generate or use 0 */
XMEMSET(&ivField, 0, sizeof(ivField));
if (useIv) {
/* Encode IV into private buffer */
XMEMSET(&packet, 0, sizeof(packet));
packet.buf = &priv->buffer[integritySz];
packet.size = sizeof(priv->buffer) - integritySz;
TPM2_Packet_AppendU16(&packet, ivField.size);
TPM2_Packet_AppendBytes(&packet, ivField.buffer, ivField.size);
ivSz = packet.pos;
}
/* Encode sensitive into private buffer */
XMEMSET(&packet, 0, sizeof(packet));
packet.buf = &priv->buffer[integritySz + ivSz];
packet.size = sizeof(priv->buffer) - (integritySz + ivSz);
TPM2_Packet_AppendSensitive(&packet, sens);
sensSz = packet.pos;
priv->size = integritySz + ivSz + sensSz;
sensitiveData = &priv->buffer[integritySz];
sensSz = ivSz + sensSz;
if (innerWrap) {
/* TODO: Inner wrap support */
}
if (outerWrap) {
/* Generate symmetric key for encryption of inner values */
symKey.size = (symKey.size + 7) / 8; /* convert to byte and round up */
rc = TPM2_KDFa(nameAlg, symSeed, "STORAGE", (TPM2B_NONCE*)name,
NULL, symKey.buffer, symKey.size);
if (rc != symKey.size) {
#ifdef DEBUG_WOLFTPM
printf("KDFa STORAGE Gen Error %d\n", rc);
#endif
return TPM_RC_FAILURE;
}
/* Encrypt the Sensitive Area using the generated symmetric key */
rc = wc_AesInit(&enc, NULL, INVALID_DEVID);
if (rc == 0) {
rc = wc_AesSetKey(&enc, symKey.buffer, symKey.size,
ivField.size == 0 ? NULL : ivField.buffer, AES_ENCRYPTION);
if (rc == 0) {
/* use inline encryption for both IV and sensitive */
rc = wc_AesCfbEncrypt(&enc, sensitiveData, sensitiveData, sensSz);
}
wc_AesFree(&enc);
}
if (rc != 0) {
#ifdef DEBUG_WOLFTPM
printf("SensitiveToPrivate AES error %d!\n", rc);
#endif
return rc;
}
/* Generate HMAC key for generation of the integrity value */
hmacKey.size = digestSz;
rc = TPM2_KDFa(nameAlg, symSeed, "INTEGRITY", NULL, NULL,
hmacKey.buffer, hmacKey.size);
if (rc != hmacKey.size) {
#ifdef DEBUG_WOLFTPM
printf("KDFa INTEGRITY Gen Error %d\n", rc);
#endif
return rc;
}
/* setup HMAC */
rc = wc_HmacInit(&hmac_ctx, NULL, INVALID_DEVID);
if (rc == 0) {
/* start HMAC */
rc = wc_HmacSetKey(&hmac_ctx, TPM2_GetHashType(nameAlg),
hmacKey.buffer, hmacKey.size);
/* consume IV and sensitive area */
if (rc == 0)
rc = wc_HmacUpdate(&hmac_ctx, sensitiveData, sensSz);
/* consume name field */
if (rc == 0)
rc = wc_HmacUpdate(&hmac_ctx, name->name, name->size);
if (rc == 0)
rc = wc_HmacFinal(&hmac_ctx, &priv->buffer[sizeof(word16)]);
wc_HmacFree(&hmac_ctx);
}
if (rc != 0) {
#ifdef DEBUG_WOLFTPM
printf("SensitiveToPrivate HMAC error %d!\n", rc);
#endif
return rc;
}
/* store the size of the integrity */
digestSz = TPM2_Packet_SwapU16(digestSz);
XMEMCPY(&priv->buffer[0], &digestSz, sizeof(word16));
}
#else
rc = NOT_COMPILED_IN;
(void)sens;
(void)priv;
(void)nameAlg;
(void)name;
(void)parentKey;
(void)sym;
(void)symSeed;
(void)useIv;
#endif
return rc;
}
int wolfTPM2_SensitiveToPrivate(TPM2B_SENSITIVE* sens, TPM2B_PRIVATE* priv,
TPMI_ALG_HASH nameAlg, TPM2B_NAME* name, const WOLFTPM2_KEY* parentKey,
TPMT_SYM_DEF_OBJECT* sym, TPM2B_DATA* symSeed)
{
return SensitiveToPrivate(sens, priv, nameAlg, name, parentKey, sym,
symSeed, 0);
}
/* Import external private key */
int wolfTPM2_ImportPrivateKey(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* parentKey,
WOLFTPM2_KEYBLOB* keyBlob, const TPM2B_PUBLIC* pub, TPM2B_SENSITIVE* sens)
{
int rc;
Import_In importIn;
Import_Out importOut;
TPM2B_NAME name;
TPM_HANDLE parentHandle;
TPM2B_DATA symSeed;
if (dev == NULL || keyBlob == NULL || pub == NULL ||
sens == NULL) {
return BAD_FUNC_ARG;
}
/* set session auth for key */
if (parentKey != NULL) {
/* set session auth for parent key */
wolfTPM2_SetAuthHandle(dev, 0, &parentKey->handle);
parentHandle = parentKey->handle.hndl;
}
else {
parentHandle = TPM_RH_OWNER;
}
/* Import private key */
XMEMSET(&importIn, 0, sizeof(importIn));
importIn.parentHandle = parentHandle;
wolfTPM2_CopyPub(&importIn.objectPublic, pub);
importIn.symmetricAlg.algorithm = TPM_ALG_NULL;
rc = wolfTPM2_ComputeName(pub, &name);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_ComputeName: failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
/* Get symmetric seed for KDFa */
XMEMSET(&symSeed, 0, sizeof(symSeed));
rc = wolfTPM2_EncryptSecret(dev, parentKey, &symSeed, &importIn.inSymSeed,
"DUPLICATE");
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_EncryptSecret: failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
/* Encrypt sensitive */
rc = wolfTPM2_SensitiveToPrivate(sens, &importIn.duplicate,
pub->publicArea.nameAlg, &name, parentKey, &importIn.symmetricAlg,
&symSeed);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_SensitiveToPrivate: failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
rc = TPM2_Import(&importIn, &importOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_Import: failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
wolfTPM2_CopySymmetric(&keyBlob->handle.symmetric,
&importIn.objectPublic.publicArea.parameters.asymDetail.symmetric);
wolfTPM2_CopyPub(&keyBlob->pub, &importIn.objectPublic);
wolfTPM2_CopyPriv(&keyBlob->priv, &importOut.outPrivate);
return rc;
}
/* Import and Load external private key to TPM */
int wolfTPM2_LoadPrivateKey(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* parentKey,
WOLFTPM2_KEY* key, const TPM2B_PUBLIC* pub, TPM2B_SENSITIVE* sens)
{
int rc;
WOLFTPM2_KEYBLOB keyBlob;
if (dev == NULL || key == NULL || pub == NULL || sens == NULL) {
return BAD_FUNC_ARG;
}
XMEMCPY(&keyBlob, key, sizeof(WOLFTPM2_KEY));
rc = wolfTPM2_ImportPrivateKey(dev, parentKey, &keyBlob, pub, sens);
if (rc == 0) {
WOLFTPM2_HANDLE parentHandle_lcl, *parentHandle = &parentHandle_lcl;
if (parentKey != NULL) {
parentHandle = (WOLFTPM2_HANDLE*)&parentKey->handle;
}
else {
XMEMSET(parentHandle, 0, sizeof(*parentHandle));
parentHandle->hndl = TPM_RH_OWNER;
}
rc = wolfTPM2_LoadKey(dev, &keyBlob, parentHandle);
}
/* return loaded key */
key->handle.hndl = keyBlob.handle.hndl;
wolfTPM2_CopyName(&key->handle.name, &keyBlob.handle.name);
wolfTPM2_CopySymmetric(&key->handle.symmetric, &keyBlob.handle.symmetric);
wolfTPM2_CopyPub(&key->pub, &keyBlob.pub);
wolfTPM2_CopyAuth(&key->handle.auth, &sens->sensitiveArea.authValue);
return rc;
}
int wolfTPM2_LoadRsaPublicKey_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
const byte* rsaPub, word32 rsaPubSz, word32 exponent,
TPMI_ALG_RSA_SCHEME scheme, TPMI_ALG_HASH hashAlg)
{
TPM2B_PUBLIC pub;
if (dev == NULL || key == NULL || rsaPub == NULL)
return BAD_FUNC_ARG;
if (rsaPubSz > sizeof(pub.publicArea.unique.rsa.buffer))
return BUFFER_E;
/* To support TPM hardware and firmware versions that do not allow
small exponents */
#ifndef WOLFTPM_NO_SOFTWARE_RSA
/* The TPM reference implementation does not support an exponent size
smaller than 7 nor does it allow keys to be created on the TPM with a
public exponent less than 2^16 + 1. */
if (exponent < 7) {
#ifdef DEBUG_WOLFTPM
printf("TPM based RSA with exponent %u not allowed! Using soft RSA\n",
exponent);
#endif
return TPM_RC_KEY;
}
#endif
XMEMSET(&pub, 0, sizeof(pub));
pub.publicArea.type = TPM_ALG_RSA;
/* make sure nameAlg is set for ticket */
pub.publicArea.nameAlg = WOLFTPM2_WRAP_DIGEST;
pub.publicArea.objectAttributes = (TPMA_OBJECT_sign | TPMA_OBJECT_decrypt |
TPMA_OBJECT_userWithAuth | TPMA_OBJECT_noDA | TPMA_OBJECT_stClear);
pub.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_NULL;
pub.publicArea.parameters.rsaDetail.keyBits = rsaPubSz * 8;
pub.publicArea.parameters.rsaDetail.exponent = exponent;
pub.publicArea.parameters.rsaDetail.scheme.scheme = scheme;
pub.publicArea.parameters.rsaDetail.scheme.details.anySig.hashAlg = hashAlg;
pub.publicArea.unique.rsa.size = rsaPubSz;
XMEMCPY(pub.publicArea.unique.rsa.buffer, rsaPub, rsaPubSz);
return wolfTPM2_LoadPublicKey(dev, key, &pub);
}
int wolfTPM2_LoadRsaPublicKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
const byte* rsaPub, word32 rsaPubSz, word32 exponent)
{
return wolfTPM2_LoadRsaPublicKey_ex(dev, key, rsaPub, rsaPubSz, exponent,
TPM_ALG_NULL, TPM_ALG_NULL);
}
int wolfTPM2_ImportRsaPrivateKeySeed(WOLFTPM2_DEV* dev,
const WOLFTPM2_KEY* parentKey, WOLFTPM2_KEYBLOB* keyBlob, const byte* rsaPub,
word32 rsaPubSz, word32 exponent, const byte* rsaPriv, word32 rsaPrivSz,
TPMI_ALG_RSA_SCHEME scheme, TPMI_ALG_HASH hashAlg, TPMA_OBJECT attributes,
byte* seed, word32 seedSz)
{
TPM2B_PUBLIC pub;
TPM2B_SENSITIVE sens;
word32 digestSz;
if (dev == NULL || keyBlob == NULL || rsaPub == NULL || rsaPriv == NULL)
return BAD_FUNC_ARG;
if (rsaPubSz > sizeof(pub.publicArea.unique.rsa.buffer))
return BUFFER_E;
if (rsaPrivSz > sizeof(sens.sensitiveArea.sensitive.rsa.buffer))
return BUFFER_E;
/* Set up public key */
XMEMSET(&pub, 0, sizeof(pub));
pub.publicArea.type = TPM_ALG_RSA;
pub.publicArea.nameAlg = WOLFTPM2_WRAP_DIGEST;
pub.publicArea.objectAttributes = attributes;
pub.publicArea.parameters.rsaDetail.keyBits = rsaPubSz * 8;
pub.publicArea.parameters.rsaDetail.exponent = exponent;
pub.publicArea.parameters.rsaDetail.scheme.scheme = scheme;
pub.publicArea.parameters.rsaDetail.scheme.details.anySig.hashAlg = hashAlg;
pub.publicArea.unique.rsa.size = rsaPubSz;
XMEMCPY(pub.publicArea.unique.rsa.buffer, rsaPub, rsaPubSz);
/* For fixedParent or (decrypt and restricted) enable symmetric */
if ((attributes & TPMA_OBJECT_fixedParent) ||
((attributes & TPMA_OBJECT_decrypt) &&
(attributes & TPMA_OBJECT_restricted))) {
pub.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES;
pub.publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128;
pub.publicArea.parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_CFB;
}
else {
pub.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_NULL;
}
/* Set up private key */
XMEMSET(&sens, 0, sizeof(sens));
sens.sensitiveArea.sensitiveType = TPM_ALG_RSA;
if (keyBlob->handle.auth.size > 0) {
sens.sensitiveArea.authValue.size = keyBlob->handle.auth.size;
XMEMCPY(sens.sensitiveArea.authValue.buffer, keyBlob->handle.auth.buffer,
keyBlob->handle.auth.size);
}
sens.sensitiveArea.sensitive.rsa.size = rsaPrivSz;
XMEMCPY(sens.sensitiveArea.sensitive.rsa.buffer, rsaPriv, rsaPrivSz);
/* Use Seed */
digestSz = TPM2_GetHashDigestSize(pub.publicArea.nameAlg);
if (seed != NULL) {
/* use custom seed */
if (seedSz != digestSz) {
#ifdef DEBUG_WOLFTPM
printf("Import RSA seed size invalid! %d != %d\n",
seedSz, digestSz);
#endif
return BAD_FUNC_ARG;
}
sens.sensitiveArea.seedValue.size = seedSz;
XMEMCPY(sens.sensitiveArea.seedValue.buffer, seed, seedSz);
}
else {
/* assign random seed */
sens.sensitiveArea.seedValue.size = digestSz;
TPM2_GetNonce(sens.sensitiveArea.seedValue.buffer,
sens.sensitiveArea.seedValue.size);
}
return wolfTPM2_ImportPrivateKey(dev, parentKey, keyBlob, &pub, &sens);
}
int wolfTPM2_ImportRsaPrivateKey(WOLFTPM2_DEV* dev,
const WOLFTPM2_KEY* parentKey, WOLFTPM2_KEYBLOB* keyBlob, const byte* rsaPub,
word32 rsaPubSz, word32 exponent, const byte* rsaPriv, word32 rsaPrivSz,
TPMI_ALG_RSA_SCHEME scheme, TPMI_ALG_HASH hashAlg)
{
TPMA_OBJECT attributes = (TPMA_OBJECT_sign | TPMA_OBJECT_decrypt |
TPMA_OBJECT_userWithAuth | TPMA_OBJECT_noDA);
return wolfTPM2_ImportRsaPrivateKeySeed(dev, parentKey, keyBlob,
rsaPub, rsaPubSz, exponent, rsaPriv, rsaPrivSz, scheme, hashAlg,
attributes, NULL, 0);
}
int wolfTPM2_LoadRsaPrivateKey_ex(WOLFTPM2_DEV* dev,
const WOLFTPM2_KEY* parentKey, WOLFTPM2_KEY* key, const byte* rsaPub,
word32 rsaPubSz, word32 exponent, const byte* rsaPriv, word32 rsaPrivSz,
TPMI_ALG_RSA_SCHEME scheme, TPMI_ALG_HASH hashAlg)
{
int rc;
WOLFTPM2_KEYBLOB keyBlob;
if (dev == NULL || key == NULL || rsaPub == NULL || rsaPriv == NULL)
return BAD_FUNC_ARG;
XMEMCPY(&keyBlob, key, sizeof(WOLFTPM2_KEY));
rc = wolfTPM2_ImportRsaPrivateKey(dev, parentKey, &keyBlob, rsaPub, rsaPubSz,
exponent, rsaPriv, rsaPrivSz, scheme, hashAlg);
if (rc == 0) {
rc = wolfTPM2_LoadKey(dev, &keyBlob,
(WOLFTPM2_HANDLE*)&parentKey->handle);
}
/* return loaded key */
wolfTPM2_CopyKeyFromBlob(key, &keyBlob);
return rc;
}
int wolfTPM2_LoadRsaPrivateKey(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* parentKey,
WOLFTPM2_KEY* key, const byte* rsaPub, word32 rsaPubSz, word32 exponent,
const byte* rsaPriv, word32 rsaPrivSz)
{
return wolfTPM2_LoadRsaPrivateKey_ex(dev, parentKey, key, rsaPub, rsaPubSz,
exponent, rsaPriv, rsaPrivSz, TPM_ALG_NULL, TPM_ALG_NULL);
}
int wolfTPM2_LoadEccPublicKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, int curveId,
const byte* eccPubX, word32 eccPubXSz, const byte* eccPubY, word32 eccPubYSz)
{
TPM2B_PUBLIC pub;
if (dev == NULL || key == NULL || eccPubX == NULL || eccPubY == NULL)
return BAD_FUNC_ARG;
if (eccPubXSz > sizeof(pub.publicArea.unique.ecc.x.buffer))
return BUFFER_E;
if (eccPubYSz > sizeof(pub.publicArea.unique.ecc.y.buffer))
return BUFFER_E;
XMEMSET(&pub, 0, sizeof(pub));
pub.publicArea.type = TPM_ALG_ECC;
/* make sure nameAlg is set for ticket */
pub.publicArea.nameAlg = WOLFTPM2_WRAP_DIGEST;
pub.publicArea.objectAttributes = TPMA_OBJECT_sign | TPMA_OBJECT_noDA;
pub.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL;
pub.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_ECDSA;
pub.publicArea.parameters.eccDetail.scheme.details.ecdsa.hashAlg =
WOLFTPM2_WRAP_DIGEST;
pub.publicArea.parameters.eccDetail.curveID = curveId;
pub.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
pub.publicArea.unique.ecc.x.size = eccPubXSz;
XMEMCPY(pub.publicArea.unique.ecc.x.buffer, eccPubX, eccPubXSz);
pub.publicArea.unique.ecc.y.size = eccPubYSz;
XMEMCPY(pub.publicArea.unique.ecc.y.buffer, eccPubY, eccPubYSz);
return wolfTPM2_LoadPublicKey(dev, key, &pub);
}
int wolfTPM2_ImportEccPrivateKeySeed(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* parentKey,
WOLFTPM2_KEYBLOB* keyBlob, int curveId,
const byte* eccPubX, word32 eccPubXSz,
const byte* eccPubY, word32 eccPubYSz,
const byte* eccPriv, word32 eccPrivSz,
TPMA_OBJECT attributes, byte* seed, word32 seedSz)
{
TPM2B_PUBLIC pub;
TPM2B_SENSITIVE sens;
word32 digestSz;
if (dev == NULL || keyBlob == NULL || eccPubX == NULL || eccPubY == NULL ||
eccPriv == NULL) {
return BAD_FUNC_ARG;
}
if (eccPubXSz > sizeof(pub.publicArea.unique.ecc.x.buffer))
return BUFFER_E;
if (eccPubYSz > sizeof(pub.publicArea.unique.ecc.y.buffer))
return BUFFER_E;
if (eccPrivSz > sizeof(sens.sensitiveArea.sensitive.ecc.buffer))
return BUFFER_E;
/* Set up public key */
XMEMSET(&pub, 0, sizeof(pub));
pub.publicArea.type = TPM_ALG_ECC;
pub.publicArea.nameAlg = WOLFTPM2_WRAP_DIGEST;
pub.publicArea.objectAttributes = attributes;
pub.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL;
/* if both sign and decrypt are set then must use NULL algorithm */
pub.publicArea.parameters.eccDetail.scheme.scheme =
((attributes & TPMA_OBJECT_sign) &&
(attributes & TPMA_OBJECT_decrypt)) ?
TPM_ALG_NULL : TPM_ALG_ECDSA;
pub.publicArea.parameters.eccDetail.scheme.details.ecdsa.hashAlg =
WOLFTPM2_WRAP_DIGEST;
pub.publicArea.parameters.eccDetail.curveID = curveId;
pub.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
pub.publicArea.unique.ecc.x.size = eccPubXSz;
XMEMCPY(pub.publicArea.unique.ecc.x.buffer, eccPubX, eccPubXSz);
pub.publicArea.unique.ecc.y.size = eccPubYSz;
XMEMCPY(pub.publicArea.unique.ecc.y.buffer, eccPubY, eccPubYSz);
/* Set up private key */
XMEMSET(&sens, 0, sizeof(sens));
sens.sensitiveArea.sensitiveType = TPM_ALG_ECC;
if (keyBlob->handle.auth.size > 0) {
sens.sensitiveArea.authValue.size = keyBlob->handle.auth.size;
XMEMCPY(sens.sensitiveArea.authValue.buffer, keyBlob->handle.auth.buffer,
keyBlob->handle.auth.size);
}
sens.sensitiveArea.sensitive.ecc.size = eccPrivSz;
XMEMCPY(sens.sensitiveArea.sensitive.ecc.buffer, eccPriv, eccPrivSz);
/* Use Seed */
digestSz = TPM2_GetHashDigestSize(pub.publicArea.nameAlg);
if (seed != NULL) {
/* use custom seed */
if (seedSz != digestSz) {
#ifdef DEBUG_WOLFTPM
printf("Import ECC seed size invalid! %d != %d\n",
seedSz, digestSz);
#endif
return BAD_FUNC_ARG;
}
sens.sensitiveArea.seedValue.size = seedSz;
XMEMCPY(sens.sensitiveArea.seedValue.buffer, seed, seedSz);
}
else {
/* assign random seed */
sens.sensitiveArea.seedValue.size = digestSz;
TPM2_GetNonce(sens.sensitiveArea.seedValue.buffer,
sens.sensitiveArea.seedValue.size);
}
return wolfTPM2_ImportPrivateKey(dev, parentKey, keyBlob, &pub, &sens);
}
int wolfTPM2_ImportEccPrivateKey(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* parentKey,
WOLFTPM2_KEYBLOB* keyBlob, int curveId,
const byte* eccPubX, word32 eccPubXSz,
const byte* eccPubY, word32 eccPubYSz,
const byte* eccPriv, word32 eccPrivSz)
{
TPMA_OBJECT attributes = (TPMA_OBJECT_sign | TPMA_OBJECT_decrypt |
TPMA_OBJECT_userWithAuth | TPMA_OBJECT_noDA);
return wolfTPM2_ImportEccPrivateKeySeed(dev, parentKey, keyBlob, curveId,
eccPubX, eccPubXSz, eccPubY, eccPubYSz, eccPriv, eccPrivSz, attributes,
NULL, 0);
}
int wolfTPM2_LoadEccPrivateKey(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* parentKey,
WOLFTPM2_KEY* key, int curveId,
const byte* eccPubX, word32 eccPubXSz,
const byte* eccPubY, word32 eccPubYSz,
const byte* eccPriv, word32 eccPrivSz)
{
int rc;
WOLFTPM2_KEYBLOB keyBlob;
if (dev == NULL || key == NULL || eccPubX == NULL || eccPubY == NULL ||
eccPriv == NULL) {
return BAD_FUNC_ARG;
}
XMEMCPY(&keyBlob, key, sizeof(WOLFTPM2_KEY));
rc = wolfTPM2_ImportEccPrivateKey(dev, parentKey, &keyBlob, curveId,
eccPubX, eccPubXSz, eccPubY, eccPubYSz, eccPriv, eccPrivSz);
if (rc == 0) {
rc = wolfTPM2_LoadKey(dev, &keyBlob,
(WOLFTPM2_HANDLE*)&parentKey->handle);
}
/* return loaded key */
wolfTPM2_CopyKeyFromBlob(key, &keyBlob);
return rc;
}
int wolfTPM2_ReadPublicKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
const TPM_HANDLE handle)
{
int rc;
ReadPublic_In readPubIn;
ReadPublic_Out readPubOut;
if (dev == NULL || key == NULL)
return BAD_FUNC_ARG;
/* Read public key */
XMEMSET(&readPubIn, 0, sizeof(readPubIn));
readPubIn.objectHandle = handle;
rc = TPM2_ReadPublic(&readPubIn, &readPubOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_ReadPublic failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
#endif
return rc;
}
key->handle.hndl = readPubIn.objectHandle;
wolfTPM2_CopySymmetric(&key->handle.symmetric,
&readPubOut.outPublic.publicArea.parameters.asymDetail.symmetric);
wolfTPM2_CopyName(&key->handle.name, &readPubOut.name);
wolfTPM2_CopyPub(&key->pub, &readPubOut.outPublic);
#ifdef DEBUG_WOLFTPM
printf("TPM2_ReadPublic Handle 0x%x: pub %d, name %d, qualifiedName %d\n",
(word32)readPubIn.objectHandle,
readPubOut.outPublic.size, readPubOut.name.size,
readPubOut.qualifiedName.size);
#endif
return rc;
}
#ifndef WOLFTPM2_NO_WOLFCRYPT
#ifndef NO_ASN
#ifndef NO_RSA
int wolfTPM2_DecodeRsaDer(const byte* der, word32 derSz,
TPM2B_PUBLIC* pub, TPM2B_SENSITIVE* sens, TPMA_OBJECT attributes)
{
int rc = 0;
RsaKey key[1];
word32 idx = 0;
word32 e = 0;
byte n[RSA_MAX_SIZE / 8];
byte d[RSA_MAX_SIZE / 8];
byte p[RSA_MAX_SIZE / 8];
byte q[RSA_MAX_SIZE / 8];
word32 eSz = (word32)sizeof(e);
word32 nSz = (word32)sizeof(n);
word32 dSz = (word32)sizeof(d);
word32 pSz = (word32)sizeof(p);
word32 qSz = (word32)sizeof(q);
int isPrivateKey = 0;
XMEMSET(n, 0, sizeof(n));
XMEMSET(d, 0, sizeof(d));
XMEMSET(p, 0, sizeof(p));
XMEMSET(q, 0, sizeof(q));
if (attributes == 0) {
attributes = (TPMA_OBJECT_restricted |
TPMA_OBJECT_sensitiveDataOrigin |
TPMA_OBJECT_sign |
TPMA_OBJECT_userWithAuth |
TPMA_OBJECT_noDA);
if (sens != NULL) {
attributes |= TPMA_OBJECT_decrypt;
}
}
rc = wc_InitRsaKey(key, NULL);
if (rc == 0) {
idx = 0;
rc = wc_RsaPrivateKeyDecode(der, &idx, key, derSz);
if (rc == 0) {
isPrivateKey = 1;
}
else {
idx = 0;
rc = wc_RsaPublicKeyDecode(der, &idx, key, derSz);
}
if (rc == 0) {
if (isPrivateKey)
rc = wc_RsaExportKey(key, (byte*)&e, &eSz, n, &nSz, d, &dSz,
p, &pSz, q, &qSz);
else
rc = wc_RsaFlattenPublicKey(key, (byte*)&e, &eSz, n, &nSz);
}
if (rc == 0 && nSz > sizeof(pub->publicArea.unique.rsa.buffer))
rc = BUFFER_E;
if (rc == 0 && sens != NULL && isPrivateKey &&
qSz > sizeof(sens->sensitiveArea.sensitive.rsa.buffer))
rc = BUFFER_E;
if (rc == 0) {
/* Set up public key */
pub->publicArea.type = TPM_ALG_RSA;
pub->publicArea.nameAlg = WOLFTPM2_WRAP_DIGEST;
pub->publicArea.objectAttributes = attributes;
pub->publicArea.parameters.rsaDetail.keyBits = nSz * 8;
pub->publicArea.parameters.rsaDetail.exponent = e;
pub->publicArea.parameters.rsaDetail.scheme.scheme =
(attributes & TPMA_OBJECT_sign) ? TPM_ALG_RSASSA : TPM_ALG_NULL;
pub->publicArea.parameters.rsaDetail.scheme.details.anySig.hashAlg =
WOLFTPM2_WRAP_DIGEST;
pub->publicArea.unique.rsa.size = nSz;
XMEMCPY(pub->publicArea.unique.rsa.buffer, n, nSz);
/* For fixedParent or (decrypt and restricted) enable symmetric */
if ((attributes & TPMA_OBJECT_fixedParent) ||
((attributes & TPMA_OBJECT_decrypt) &&
(attributes & TPMA_OBJECT_restricted))) {
pub->publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES;
pub->publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128;
pub->publicArea.parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_CFB;
}
else {
pub->publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_NULL;
}
/* Set up private key */
if (sens != NULL && isPrivateKey) {
sens->sensitiveArea.sensitiveType = TPM_ALG_RSA;
sens->sensitiveArea.sensitive.rsa.size = qSz;
XMEMCPY(sens->sensitiveArea.sensitive.rsa.buffer, q, qSz);
}
}
wc_FreeRsaKey(key);
}
return rc;
}
#endif
#ifdef HAVE_ECC
int wolfTPM2_DecodeEccDer(const byte* der, word32 derSz, TPM2B_PUBLIC* pub,
TPM2B_SENSITIVE* sens, TPMA_OBJECT attributes)
{
int rc;
int curveId = 0;
word32 idx;
ecc_key key[1];
byte d[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
byte qx[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
byte qy[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
word32 dSz = sizeof(d);
word32 qxSz = sizeof(qx);
word32 qySz = sizeof(qy);
int isPrivateKey = 0;
XMEMSET(d, 0, sizeof(d));
XMEMSET(qx, 0, sizeof(qx));
XMEMSET(qy, 0, sizeof(qy));
if (attributes == 0) {
attributes = (TPMA_OBJECT_restricted |
TPMA_OBJECT_sensitiveDataOrigin |
TPMA_OBJECT_sign |
TPMA_OBJECT_userWithAuth |
TPMA_OBJECT_noDA);
if (sens != NULL) {
attributes |= TPMA_OBJECT_decrypt;
}
}
rc = wc_ecc_init(key);
if (rc == 0) {
idx = 0;
rc = wc_EccPrivateKeyDecode(der, &idx, key, derSz);
if (rc == 0) {
isPrivateKey = 1;
}
else {
idx = 0;
rc = wc_EccPublicKeyDecode(der, &idx, key, derSz);
}
if (rc == 0) {
curveId = TPM2_GetTpmCurve(key->dp->id);
if (isPrivateKey)
rc = wc_ecc_export_private_raw(key, qx, &qxSz, qy, &qySz, d, &dSz);
else
rc = wc_ecc_export_public_raw(key, qx, &qxSz, qy, &qySz);
}
if (rc == 0 && qxSz > sizeof(pub->publicArea.unique.ecc.x.buffer))
rc = BUFFER_E;
if (rc == 0 && qySz > sizeof(pub->publicArea.unique.ecc.y.buffer))
rc = BUFFER_E;
if (rc == 0 && sens != NULL && isPrivateKey &&
dSz > sizeof(sens->sensitiveArea.sensitive.ecc.buffer))
rc = BUFFER_E;
if (rc == 0) {
/* Set up public key */
pub->publicArea.type = TPM_ALG_ECC;
pub->publicArea.nameAlg = WOLFTPM2_WRAP_DIGEST;
pub->publicArea.objectAttributes = attributes;
pub->publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL;
pub->publicArea.parameters.eccDetail.scheme.scheme =
(attributes & TPMA_OBJECT_sign) ? TPM_ALG_ECDSA : TPM_ALG_NULL;
pub->publicArea.parameters.eccDetail.scheme.details.ecdsa.hashAlg =
WOLFTPM2_WRAP_DIGEST;
pub->publicArea.parameters.eccDetail.curveID = curveId;
pub->publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
pub->publicArea.unique.ecc.x.size = qxSz;
XMEMCPY(pub->publicArea.unique.ecc.x.buffer, qx, qxSz);
pub->publicArea.unique.ecc.y.size = qySz;
XMEMCPY(pub->publicArea.unique.ecc.y.buffer, qy, qySz);
/* For fixedParent or (decrypt and restricted) enable symmetric */
if ((attributes & TPMA_OBJECT_fixedParent) ||
((attributes & TPMA_OBJECT_decrypt) &&
(attributes & TPMA_OBJECT_restricted))) {
pub->publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_AES;
pub->publicArea.parameters.eccDetail.symmetric.keyBits.aes = 128;
pub->publicArea.parameters.eccDetail.symmetric.mode.aes = TPM_ALG_CFB;
}
else {
pub->publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL;
}
/* Set up private key */
if (sens != NULL && isPrivateKey) {
sens->sensitiveArea.sensitiveType = TPM_ALG_ECC;
sens->sensitiveArea.sensitive.ecc.size = dSz;
XMEMCPY(sens->sensitiveArea.sensitive.ecc.buffer, d, dSz);
}
}
wc_ecc_free(key);
}
return rc;
}
#endif /* HAVE_ECC */
int wolfTPM2_ExportPublicKeyBuffer(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* tpmKey,
int encodingType, byte* out, word32* outSz)
{
int rc;
word32 derSz = 0;
union keyUnion {
#ifndef NO_RSA
RsaKey rsa;
#endif
#ifdef HAVE_ECC
ecc_key ecc;
#endif
} key;
if (dev == NULL || tpmKey == NULL) {
return BAD_FUNC_ARG;
}
XMEMSET(&key, 0, sizeof(key));
/* determine the type of key in WOLFTPM2_KEY */
if (tpmKey->pub.publicArea.type == TPM_ALG_ECC) {
#if defined(HAVE_ECC) && \
defined(HAVE_ECC_KEY_IMPORT) && defined(HAVE_ECC_KEY_EXPORT)
rc = wc_ecc_init(&key.ecc);
if (rc == 0) {
/* load public portion of key into wolf ECC Key */
rc = wolfTPM2_EccKey_TpmToWolf(dev, tpmKey, &key.ecc);
if (rc == 0) {
rc = wc_EccPublicKeyToDer(&key.ecc, out, *outSz, 1);
if (rc > 0) {
derSz = rc;
rc = 0;
}
else {
rc = BUFFER_E;
}
}
}
#else
rc = NOT_COMPILED_IN;
#endif
}
else if (tpmKey->pub.publicArea.type == TPM_ALG_RSA) {
/* RSA public key export only enabled with:
* cert gen, key gen or openssl extra */
#if !defined(NO_RSA) && \
(defined(WOLFSSL_CERT_GEN) || defined(OPENSSL_EXTRA) || \
defined(WOLFSSL_KEY_GEN))
rc = wc_InitRsaKey(&key.rsa, NULL);
if (rc == 0) {
/* load public portion of key into wolf RSA Key */
rc = wolfTPM2_RsaKey_TpmToWolf(dev, tpmKey, &key.rsa);
if (rc == 0) {
rc = wc_RsaKeyToPublicDer_ex(&key.rsa, out, *outSz, 1);
if (rc > 0) {
derSz = rc;
rc = 0;
}
else {
rc = BUFFER_E;
}
}
}
#else
rc = NOT_COMPILED_IN;
#endif
}
else {
#ifdef DEBUG_WOLFTPM
printf("Invalid tpmKey type!\n");
#endif
rc = BAD_FUNC_ARG;
}
/* Optionally convert to PEM */
if (rc == 0 && encodingType == ENCODING_TYPE_PEM) {
#ifdef WOLFSSL_DER_TO_PEM
WOLFTPM2_BUFFER tmp;
if (derSz > (word32)sizeof(tmp.buffer)) {
rc = BUFFER_E;
}
else {
/* move DER to temp variable */
tmp.size = derSz;
XMEMCPY(tmp.buffer, out, derSz);
XMEMSET(out, 0, *outSz);
rc = wc_DerToPem(tmp.buffer, tmp.size, out, *outSz, PUBLICKEY_TYPE);
if (rc > 0) {
*outSz = rc;
rc = 0;
}
else {
rc = BUFFER_E;
}
}
#else
rc = NOT_COMPILED_IN;
#endif
}
else if (rc == 0) {
*outSz = derSz;
}
return rc;
}
int wolfTPM2_ImportPublicKeyBuffer(WOLFTPM2_DEV* dev, int keyType,
WOLFTPM2_KEY* key, int encodingType, const char* input, word32 inSz,
TPMA_OBJECT objectAttributes)
{
int rc = 0;
byte* derBuf;
word32 derSz;
if (dev == NULL || key == NULL || input == NULL || inSz == 0) {
return BAD_FUNC_ARG;
}
if (encodingType == ENCODING_TYPE_PEM) {
#ifdef WOLFTPM2_PEM_DECODE
/* der size is base 64 decode length */
derSz = inSz * 3 / 4 + 1;
derBuf = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (derBuf == NULL)
return MEMORY_E;
rc = wc_PubKeyPemToDer((byte*)input, inSz, derBuf, derSz);
if (rc >= 0) {
derSz = rc;
rc = 0;
}
#else
return NOT_COMPILED_IN;
#endif
}
else { /* ASN.1 (DER) */
derBuf = (byte*)input;
derSz = inSz;
}
/* Handle DER Import */
if (keyType == TPM_ALG_RSA) {
#ifndef NO_RSA
rc = wolfTPM2_DecodeRsaDer(derBuf, derSz, &key->pub, NULL, objectAttributes);
#else
rc = NOT_COMPILED_IN;
#endif
}
else if (keyType == TPM_ALG_ECC) {
#ifdef HAVE_ECC
rc = wolfTPM2_DecodeEccDer(derBuf, derSz, &key->pub, NULL, objectAttributes);
#else
rc = NOT_COMPILED_IN;
#endif
}
#ifdef WOLFTPM2_PEM_DECODE
if (derBuf != (byte*)input) {
XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
#endif
return rc;
}
int wolfTPM2_ImportPrivateKeyBuffer(WOLFTPM2_DEV* dev,
const WOLFTPM2_KEY* parentKey, int keyType, WOLFTPM2_KEYBLOB* keyBlob,
int encodingType, const char* input, word32 inSz, const char* pass,
TPMA_OBJECT objectAttributes, byte* seed, word32 seedSz)
{
int rc = 0;
byte* derBuf;
word32 derSz;
TPM2B_PUBLIC* pub;
TPM2B_SENSITIVE sens;
word32 digestSz;
if (dev == NULL || keyBlob == NULL || input == NULL || inSz == 0) {
return BAD_FUNC_ARG;
}
pub = &keyBlob->pub;
XMEMSET(pub, 0, sizeof(*pub));
XMEMSET(&sens, 0, sizeof(sens));
if (encodingType == ENCODING_TYPE_PEM) {
#ifdef WOLFTPM2_PEM_DECODE
/* der size is base 64 decode length */
derSz = inSz * 3 / 4 + 1;
derBuf = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (derBuf == NULL)
return MEMORY_E;
rc = wc_KeyPemToDer((byte*)input, inSz, derBuf, derSz, pass);
if (rc >= 0) {
derSz = rc;
rc = 0;
}
#else
(void)pass;
return NOT_COMPILED_IN;
#endif
}
else { /* ASN.1 (DER) */
derBuf = (byte*)input;
derSz = inSz;
}
/* Handle DER Import */
if (keyType == TPM_ALG_RSA) {
#ifndef NO_RSA
rc = wolfTPM2_DecodeRsaDer(derBuf, derSz, pub, &sens, objectAttributes);
#else
rc = NOT_COMPILED_IN;
#endif
}
else if (keyType == TPM_ALG_ECC) {
#ifdef HAVE_ECC
rc = wolfTPM2_DecodeEccDer(derBuf, derSz, pub, &sens, objectAttributes);
#else
rc = NOT_COMPILED_IN;
#endif
}
if (rc == 0 && parentKey != NULL) {
/* Setup private key */
if (keyBlob->handle.auth.size > 0) {
sens.sensitiveArea.authValue.size = keyBlob->handle.auth.size;
XMEMCPY(sens.sensitiveArea.authValue.buffer,
keyBlob->handle.auth.buffer, keyBlob->handle.auth.size);
}
/* Use Seed */
digestSz = TPM2_GetHashDigestSize(pub->publicArea.nameAlg);
if (seed != NULL) {
/* use custom seed */
if (seedSz != digestSz) {
#ifdef DEBUG_WOLFTPM
printf("Import %s seed size invalid! %d != %d\n",
TPM2_GetAlgName(keyType), seedSz, digestSz);
#endif
return BAD_FUNC_ARG;
}
sens.sensitiveArea.seedValue.size = seedSz;
XMEMCPY(sens.sensitiveArea.seedValue.buffer, seed, seedSz);
}
else {
/* assign random seed */
sens.sensitiveArea.seedValue.size = digestSz;
TPM2_GetNonce(sens.sensitiveArea.seedValue.buffer,
sens.sensitiveArea.seedValue.size);
}
/* Import Private Key */
rc = wolfTPM2_ImportPrivateKey(dev, parentKey, keyBlob, pub, &sens);
}
#ifdef WOLFTPM2_PEM_DECODE
if (derBuf != (byte*)input) {
XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
#endif
return rc;
}
#endif /* !NO_ASN */
#ifndef NO_RSA
#ifndef NO_ASN
int wolfTPM2_RsaPrivateKeyImportDer(WOLFTPM2_DEV* dev,
const WOLFTPM2_KEY* parentKey, WOLFTPM2_KEYBLOB* keyBlob, const byte* input,
word32 inSz, TPMI_ALG_RSA_SCHEME scheme, TPMI_ALG_HASH hashAlg)
{
int rc = 0;
int initRc = -1;
RsaKey key[1];
word32 idx = 0;
word32 e;
byte n[RSA_MAX_SIZE / 8];
byte d[RSA_MAX_SIZE / 8];
byte p[RSA_MAX_SIZE / 8];
byte q[RSA_MAX_SIZE / 8];
word32 eSz = (word32)sizeof(e);
word32 nSz = (word32)sizeof(n);
word32 dSz = (word32)sizeof(d);
word32 pSz = (word32)sizeof(p);
word32 qSz = (word32)sizeof(q);
if (dev == NULL || parentKey == NULL || keyBlob == NULL || input == NULL ||
inSz == 0) {
rc = BAD_FUNC_ARG;
}
if (rc == 0)
rc = initRc = wc_InitRsaKey(key, NULL);
if (rc == 0)
rc = wc_RsaPrivateKeyDecode(input, &idx, key, inSz);
if (rc == 0) {
rc = wc_RsaExportKey(key, (byte*)&e, &eSz, n, &nSz, d, &dSz, p, &pSz, q,
&qSz);
}
if (rc == 0) {
rc = wolfTPM2_ImportRsaPrivateKey(dev, parentKey, keyBlob, n, nSz, e, q,
qSz, scheme, hashAlg);
}
if (initRc == 0)
wc_FreeRsaKey(key);
return rc;
}
#endif /* !NO_ASN */
#ifdef WOLFTPM2_PEM_DECODE
int wolfTPM2_RsaPrivateKeyImportPem(WOLFTPM2_DEV* dev,
const WOLFTPM2_KEY* parentKey, WOLFTPM2_KEYBLOB* keyBlob,
const char* input, word32 inSz, char* pass,
TPMI_ALG_RSA_SCHEME scheme, TPMI_ALG_HASH hashAlg)
{
(void)scheme;
(void)hashAlg;
return wolfTPM2_ImportPrivateKeyBuffer(dev, parentKey, TPM_ALG_RSA, keyBlob,
ENCODING_TYPE_PEM, input, inSz, pass, 0, NULL, 0);
}
#endif /* WOLFTPM2_PEM_DECODE */
int wolfTPM2_RsaKey_TpmToWolf(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* tpmKey,
RsaKey* wolfKey)
{
int rc;
word32 exponent;
byte e[sizeof(exponent)];
byte n[WOLFTPM2_WRAP_RSA_KEY_BITS / 8];
word32 eSz = sizeof(e);
word32 nSz = sizeof(n);
if (dev == NULL || tpmKey == NULL || wolfKey == NULL)
return BAD_FUNC_ARG;
XMEMSET(e, 0, sizeof(e));
XMEMSET(n, 0, sizeof(n));
/* load exponent */
exponent = tpmKey->pub.publicArea.parameters.rsaDetail.exponent;
if (exponent == 0)
exponent = RSA_DEFAULT_PUBLIC_EXPONENT;
e[3] = (exponent >> 24) & 0xFF;
e[2] = (exponent >> 16) & 0xFF;
e[1] = (exponent >> 8) & 0xFF;
e[0] = exponent & 0xFF;
eSz = e[3] ? 4 : e[2] ? 3 : e[1] ? 2 : e[0] ? 1 : 0; /* calc size */
/* load public key */
nSz = tpmKey->pub.publicArea.unique.rsa.size;
XMEMCPY(n, tpmKey->pub.publicArea.unique.rsa.buffer, nSz);
/* load public key portion into wolf RsaKey */
rc = wc_RsaPublicKeyDecodeRaw(n, nSz, e, eSz, wolfKey);
return rc;
}
int wolfTPM2_RsaKey_TpmToPemPub(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* tpmKey,
byte* pem, word32* pemSz)
{
return wolfTPM2_ExportPublicKeyBuffer(dev, tpmKey,
ENCODING_TYPE_PEM, pem, pemSz);
}
static word32 wolfTPM2_RsaKey_Exponent(byte* e, word32 eSz)
{
word32 exponent = 0, i;
for (i=0; i<eSz && i<sizeof(word32); i++) {
exponent |= ((word32)e[i]) << (i*8);
}
return exponent;
}
int wolfTPM2_RsaKey_WolfToTpm_ex(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* parentKey,
RsaKey* wolfKey, WOLFTPM2_KEY* tpmKey)
{
int rc;
word32 exponent;
byte e[sizeof(exponent)];
byte n[WOLFTPM2_WRAP_RSA_KEY_BITS / 8];
word32 eSz = sizeof(e);
word32 nSz = sizeof(n);
if (dev == NULL || tpmKey == NULL || wolfKey == NULL)
return BAD_FUNC_ARG;
XMEMSET(e, 0, sizeof(e));
XMEMSET(n, 0, sizeof(n));
if (parentKey && wolfKey->type == RSA_PRIVATE) {
byte d[WOLFTPM2_WRAP_RSA_KEY_BITS / 8];
byte p[WOLFTPM2_WRAP_RSA_KEY_BITS / 8];
byte q[WOLFTPM2_WRAP_RSA_KEY_BITS / 8];
word32 dSz = sizeof(d);
word32 pSz = sizeof(p);
word32 qSz = sizeof(q);
XMEMSET(d, 0, sizeof(d));
XMEMSET(p, 0, sizeof(p));
XMEMSET(q, 0, sizeof(q));
/* export the raw private and public RSA as unsigned binary */
PRIVATE_KEY_UNLOCK();
rc = wc_RsaExportKey(wolfKey, e, &eSz, n, &nSz,
d, &dSz, p, &pSz, q, &qSz);
PRIVATE_KEY_LOCK();
if (rc == 0) {
exponent = wolfTPM2_RsaKey_Exponent(e, eSz);
rc = wolfTPM2_LoadRsaPrivateKey(dev, parentKey, tpmKey, n, nSz,
exponent, q, qSz);
}
/* not used */
(void)p;
}
else {
/* export the raw public RSA portion */
rc = wc_RsaFlattenPublicKey(wolfKey, e, &eSz, n, &nSz);
if (rc == 0) {
exponent = wolfTPM2_RsaKey_Exponent(e, eSz);
rc = wolfTPM2_LoadRsaPublicKey(dev, tpmKey, n, nSz, exponent);
}
}
return rc;
}
int wolfTPM2_RsaKey_WolfToTpm(WOLFTPM2_DEV* dev, RsaKey* wolfKey,
WOLFTPM2_KEY* tpmKey)
{
return wolfTPM2_RsaKey_WolfToTpm_ex(dev, NULL, wolfKey, tpmKey);
}
int wolfTPM2_RsaKey_PubPemToTpm(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* tpmKey,
const byte* pem, word32 pemSz)
{
int rc = TPM_RC_FAILURE;
#ifdef WOLFTPM2_PEM_DECODE
RsaKey rsaKey;
#endif
if (dev == NULL || tpmKey == NULL || pem == NULL)
return BAD_FUNC_ARG;
#ifdef WOLFTPM2_PEM_DECODE
/* Prepare wolfCrypt key structure */
rc = wc_InitRsaKey(&rsaKey, NULL);
if (rc == 0) {
/* allocate buffer for DER */
word32 derSz = pemSz; /* DER is always smaller */
byte* derBuf = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (derBuf == NULL) {
rc = MEMORY_E;
}
if (rc == 0) {
/* Convert PEM format key from file to DER - inline okay */
rc = wc_PubKeyPemToDer(pem, pemSz, derBuf, derSz);
}
if (rc >= 0) {
/* Convert DER to wolfCrypt file */
word32 idx = 0;
derSz = (word32)rc;
rc = wc_RsaPublicKeyDecode(derBuf, &idx, &rsaKey, derSz);
}
if (rc == 0) {
/* Load into the TPM */
rc = wolfTPM2_RsaKey_WolfToTpm(dev, &rsaKey, tpmKey);
}
XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
wc_FreeRsaKey(&rsaKey);
}
#else
(void)pemSz;
#endif
return rc;
}
#endif /* !NO_RSA */
#ifdef HAVE_ECC
#ifdef HAVE_ECC_KEY_IMPORT
int wolfTPM2_EccKey_TpmToWolf(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* tpmKey,
ecc_key* wolfKey)
{
int rc, curve_id;
byte qx[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
byte qy[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
word32 qxSz = sizeof(qx);
word32 qySz = sizeof(qy);
if (dev == NULL || tpmKey == NULL || wolfKey == NULL)
return BAD_FUNC_ARG;
XMEMSET(qx, 0, sizeof(qx));
XMEMSET(qy, 0, sizeof(qy));
/* load curve type */
curve_id = tpmKey->pub.publicArea.parameters.eccDetail.curveID;
rc = TPM2_GetWolfCurve(curve_id);
if (rc < 0)
return rc;
curve_id = rc;
/* load public key */
qxSz = tpmKey->pub.publicArea.unique.ecc.x.size;
XMEMCPY(qx, tpmKey->pub.publicArea.unique.ecc.x.buffer, qxSz);
qySz = tpmKey->pub.publicArea.unique.ecc.y.size;
XMEMCPY(qy, tpmKey->pub.publicArea.unique.ecc.y.buffer, qySz);
/* load public key portion into wolf ecc_key */
rc = wc_ecc_import_unsigned(wolfKey, qx, qy, NULL, curve_id);
return rc;
}
#endif /* HAVE_ECC_KEY_IMPORT */
#ifdef HAVE_ECC_KEY_EXPORT
int wolfTPM2_EccKey_WolfToTpm_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* parentKey,
ecc_key* wolfKey, WOLFTPM2_KEY* tpmKey)
{
int rc, curve_id = 0;
byte qx[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
byte qy[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
word32 qxSz = sizeof(qx);
word32 qySz = sizeof(qy);
if (dev == NULL || tpmKey == NULL || wolfKey == NULL)
return BAD_FUNC_ARG;
XMEMSET(tpmKey, 0, sizeof(*tpmKey));
XMEMSET(qx, 0, sizeof(qx));
XMEMSET(qy, 0, sizeof(qy));
if (wolfKey->dp)
curve_id = wolfKey->dp->id;
rc = TPM2_GetTpmCurve(curve_id);
if (rc < 0)
return rc;
curve_id = rc;
rc = 0;
if (parentKey && wolfKey->type != ECC_PUBLICKEY) {
byte d[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
word32 dSz = sizeof(d);
XMEMSET(d, 0, sizeof(d));
if (wolfKey->type == ECC_PRIVATEKEY_ONLY) {
/* compute public point without modifying incoming wolf key */
int keySz = wc_ecc_size(wolfKey);
ecc_point* point = wc_ecc_new_point();
if (point == NULL) {
rc = MEMORY_E;
}
if (rc == 0) {
#ifdef ECC_TIMING_RESISTANT
rc = wc_ecc_make_pub_ex(wolfKey, point, wolfKey->rng);
#else
rc = wc_ecc_make_pub(wolfKey, point);
#endif
if (rc == 0)
rc = wc_export_int(point->x, qx, &qxSz, keySz,
WC_TYPE_UNSIGNED_BIN);
if (rc == 0)
rc = wc_export_int(point->y, qy, &qySz, keySz,
WC_TYPE_UNSIGNED_BIN);
if (rc == 0)
rc = wc_ecc_export_private_only(wolfKey, d, &dSz);
wc_ecc_del_point(point);
}
}
else {
/* export the raw private/public ECC portions */
rc = wc_ecc_export_private_raw(wolfKey,
qx, &qxSz,
qy, &qySz,
d, &dSz);
}
if (rc == 0) {
rc = wolfTPM2_LoadEccPrivateKey(dev, parentKey, tpmKey, curve_id,
qx, qxSz, qy, qySz, d, dSz);
}
}
else {
/* export the raw public ECC portion */
rc = wc_ecc_export_public_raw(wolfKey, qx, &qxSz, qy, &qySz);
if (rc == 0) {
rc = wolfTPM2_LoadEccPublicKey(dev, tpmKey, curve_id, qx, qxSz,
qy, qySz);
}
}
return rc;
}
int wolfTPM2_EccKey_WolfToTpm(WOLFTPM2_DEV* dev, ecc_key* wolfKey,
WOLFTPM2_KEY* tpmKey)
{
return wolfTPM2_EccKey_WolfToTpm_ex(dev, NULL, wolfKey, tpmKey);
}
int wolfTPM2_EccKey_WolfToPubPoint(WOLFTPM2_DEV* dev, ecc_key* wolfKey,
TPM2B_ECC_POINT* pubPoint)
{
int rc;
word32 xSz, ySz;
if (dev == NULL || wolfKey == NULL || pubPoint == NULL)
return BAD_FUNC_ARG;
XMEMSET(pubPoint, 0, sizeof(TPM2B_ECC_POINT));
xSz = sizeof(pubPoint->point.x.buffer);;
ySz = sizeof(pubPoint->point.y.buffer);;
/* load wolf ECC public key into TPM2B_ECC_POINT */
rc = wc_ecc_export_public_raw(wolfKey,
pubPoint->point.x.buffer, &xSz,
pubPoint->point.y.buffer, &ySz);
if (rc == 0) {
pubPoint->point.x.size = xSz;
pubPoint->point.y.size = ySz;
}
return rc;
}
#endif /* HAVE_ECC_KEY_EXPORT */
#endif /* HAVE_ECC */
#endif /* !WOLFTPM2_NO_WOLFCRYPT */
/* primaryHandle must be owner or platform hierarchy */
/* Owner Persistent Handle Range: 0x81000000 to 0x817FFFFF */
/* Platform Persistent Handle Range: 0x81800000 to 0x81FFFFFF */
int wolfTPM2_NVStoreKey(WOLFTPM2_DEV* dev, TPM_HANDLE primaryHandle,
WOLFTPM2_KEY* key, TPM_HANDLE persistentHandle)
{
int rc;
EvictControl_In in;
if (dev == NULL || key == NULL) {
return BAD_FUNC_ARG;
}
if (primaryHandle == TPM_RH_OWNER &&
(persistentHandle < PERSISTENT_FIRST ||
persistentHandle > PERSISTENT_LAST)) {
return BAD_FUNC_ARG;
}
if (primaryHandle == TPM_RH_PLATFORM &&
(persistentHandle < PLATFORM_PERSISTENT ||
persistentHandle > PERSISTENT_LAST)) {
return BAD_FUNC_ARG;
}
/* if key is already persistent then just return success */
if (key->handle.hndl == persistentHandle)
return TPM_RC_SUCCESS;
/* set session auth to blank */
wolfTPM2_SetAuthPassword(dev, 0, NULL);
/* Move key into NV to persist */
XMEMSET(&in, 0, sizeof(in));
in.auth = primaryHandle;
in.objectHandle = key->handle.hndl;
in.persistentHandle = persistentHandle;
rc = TPM2_EvictControl(&in);
if (rc != TPM_RC_SUCCESS) {
#ifdef WOLFTPM_WINAPI
if (rc == (int)TPM_E_COMMAND_BLOCKED) { /* 0x80280400 */
#ifdef DEBUG_WOLFTPM
printf("TPM2_EvictControl (storing key to NV) not allowed on "
"Windows TBS (err 0x%x)\n", rc);
#endif
rc = TPM_RC_COMMAND_CODE;
}
#endif
#ifdef DEBUG_WOLFTPM
printf("TPM2_EvictControl failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_EvictControl Auth 0x%x, Key 0x%x, Persistent 0x%x\n",
(word32)in.auth, (word32)in.objectHandle, (word32)in.persistentHandle);
#endif
/* unload transient handle */
wolfTPM2_UnloadHandle(dev, &key->handle);
/* replace handle with persistent one */
key->handle.hndl = persistentHandle;
return rc;
}
int wolfTPM2_NVDeleteKey(WOLFTPM2_DEV* dev, TPM_HANDLE primaryHandle,
WOLFTPM2_KEY* key)
{
int rc;
EvictControl_In in;
if (dev == NULL || key == NULL || primaryHandle == 0) {
return BAD_FUNC_ARG;
}
/* if key is not persistent then just return success */
if (key->handle.hndl < PERSISTENT_FIRST ||
key->handle.hndl > PERSISTENT_LAST)
return TPM_RC_SUCCESS;
/* remove key from NV */
XMEMSET(&in, 0, sizeof(in));
in.auth = primaryHandle;
in.objectHandle = key->handle.hndl;
in.persistentHandle = key->handle.hndl;
rc = TPM2_EvictControl(&in);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_EvictControl failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_EvictControl Auth 0x%x, Key 0x%x, Persistent 0x%x\n",
(word32)in.auth, (word32)in.objectHandle, (word32)in.persistentHandle);
#endif
/* indicate no handle */
key->handle.hndl = TPM_RH_NULL;
return rc;
}
/* sigAlg: TPM_ALG_RSASSA, TPM_ALG_RSAPSS, TPM_ALG_ECDSA or TPM_ALG_ECDAA */
/* hashAlg: TPM_ALG_SHA1, TPM_ALG_SHA256, TPM_ALG_SHA384 or TPM_ALG_SHA512 */
int wolfTPM2_SignHashScheme(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
const byte* digest, int digestSz, byte* sig, int* sigSz,
TPMI_ALG_SIG_SCHEME sigAlg, TPMI_ALG_HASH hashAlg)
{
int rc;
Sign_In signIn;
Sign_Out signOut;
int curveSize = 0;
int sigOutSz = 0;
if (dev == NULL || key == NULL || digest == NULL || sig == NULL ||
sigSz == NULL) {
return BAD_FUNC_ARG;
}
if (key->pub.publicArea.type == TPM_ALG_ECC) {
/* get curve size */
curveSize = wolfTPM2_GetCurveSize(
key->pub.publicArea.parameters.eccDetail.curveID);
if (curveSize <= 0) {
return BAD_FUNC_ARG;
}
}
/* set session auth for key */
wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
XMEMSET(&signIn, 0, sizeof(signIn));
signIn.keyHandle = key->handle.hndl;
signIn.digest.size = digestSz;
XMEMCPY(signIn.digest.buffer, digest, signIn.digest.size);
signIn.inScheme.scheme = sigAlg;
signIn.inScheme.details.any.hashAlg = hashAlg;
signIn.validation.tag = TPM_ST_HASHCHECK;
signIn.validation.hierarchy = TPM_RH_NULL;
rc = TPM2_Sign(&signIn, &signOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_Sign failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
#endif
return rc;
}
if (key->pub.publicArea.type == TPM_ALG_ECC) {
/* Assemble R and S into signature (R then S) */
sigOutSz = signOut.signature.signature.ecdsa.signatureR.size +
signOut.signature.signature.ecdsa.signatureS.size;
if (sigOutSz > *sigSz) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_Sign: ECC result truncated %d -> %d\n",
sigOutSz, *sigSz);
#endif
sigOutSz = *sigSz;
}
XMEMCPY(sig,
signOut.signature.signature.ecdsa.signatureR.buffer,
signOut.signature.signature.ecdsa.signatureR.size);
XMEMCPY(sig + signOut.signature.signature.ecdsa.signatureR.size,
signOut.signature.signature.ecdsa.signatureS.buffer,
signOut.signature.signature.ecdsa.signatureS.size);
}
else if (key->pub.publicArea.type == TPM_ALG_RSA) {
/* RSA signature size and buffer (with padding depending on scheme) */
sigOutSz = signOut.signature.signature.rsassa.sig.size;
if (sigOutSz > *sigSz) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_Sign: RSA result truncated %d -> %d\n",
sigOutSz, *sigSz);
#endif
sigOutSz = *sigSz;
}
XMEMCPY(sig, signOut.signature.signature.rsassa.sig.buffer, sigOutSz);
}
*sigSz = sigOutSz;
#ifdef DEBUG_WOLFTPM
printf("TPM2_Sign: %s %d\n",
TPM2_GetAlgName(signIn.inScheme.scheme), *sigSz);
#endif
return rc;
}
int wolfTPM2_SignHash(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
const byte* digest, int digestSz, byte* sig, int* sigSz)
{
TPM_ALG_ID sigAlg = TPM_ALG_NULL;
TPMI_ALG_HASH hashAlg = WOLFTPM2_WRAP_DIGEST;
if (dev == NULL || key == NULL || digest == NULL || sig == NULL) {
return BAD_FUNC_ARG;
}
if (key->pub.publicArea.type == TPM_ALG_ECC) {
/* Keys that are created with sign and decrypt require scheme to be NULL,
* but we must supply ECDSA and Hash Algorithm for signing */
sigAlg = key->pub.publicArea.parameters.eccDetail.scheme.scheme;
hashAlg = key->pub.publicArea.parameters.eccDetail.scheme.details.any.hashAlg;
if (sigAlg == 0 || sigAlg == TPM_ALG_NULL) {
sigAlg = TPM_ALG_ECDSA;
}
if (hashAlg == 0 || hashAlg == TPM_ALG_NULL) {
if (digestSz == 64)
hashAlg = TPM_ALG_SHA512;
else if (digestSz == 48)
hashAlg = TPM_ALG_SHA384;
else if (digestSz == 32)
hashAlg = TPM_ALG_SHA256;
}
}
else if (key->pub.publicArea.type == TPM_ALG_RSA) {
sigAlg = key->pub.publicArea.parameters.rsaDetail.scheme.scheme;
hashAlg = key->pub.publicArea.parameters.rsaDetail.scheme.details.anySig.hashAlg;
}
return wolfTPM2_SignHashScheme(dev, key, digest, digestSz, sig, sigSz,
sigAlg, hashAlg);
}
/* sigAlg: TPM_ALG_RSASSA, TPM_ALG_RSAPSS, TPM_ALG_ECDSA or TPM_ALG_ECDAA */
/* hashAlg: TPM_ALG_SHA1, TPM_ALG_SHA256, TPM_ALG_SHA384 or TPM_ALG_SHA512 */
int wolfTPM2_VerifyHashTicket(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
const byte* sig, int sigSz, const byte* digest, int digestSz,
TPMI_ALG_SIG_SCHEME sigAlg, TPMI_ALG_HASH hashAlg,
TPMT_TK_VERIFIED* checkTicket)
{
int rc;
VerifySignature_In verifySigIn;
VerifySignature_Out verifySigOut;
int curveSize = 0;
if (dev == NULL || key == NULL || digest == NULL || sig == NULL) {
return BAD_FUNC_ARG;
}
if (key->pub.publicArea.type == TPM_ALG_ECC) {
if (sigAlg == TPM_ALG_NULL)
sigAlg = key->pub.publicArea.parameters.eccDetail.scheme.scheme;
/* get curve size */
curveSize = wolfTPM2_GetCurveSize(
key->pub.publicArea.parameters.eccDetail.curveID);
if (curveSize <= 0 || sigSz < (curveSize * 2)) {
return BAD_FUNC_ARG;
}
/* verify curve size cannot exceed buffer */
if (curveSize > (int)sizeof(verifySigIn.signature.signature.ecdsa.signatureR.buffer))
return BAD_FUNC_ARG;
/* hash cannot be larger than key size for TPM */
if (digestSz > curveSize)
digestSz = curveSize;
}
else if (key->pub.publicArea.type == TPM_ALG_RSA) {
if (sigAlg == TPM_ALG_NULL)
sigAlg = key->pub.publicArea.parameters.rsaDetail.scheme.scheme;
if (sigSz > (int)sizeof(verifySigIn.signature.signature.rsassa.sig.buffer))
return BAD_FUNC_ARG;
}
else {
return BAD_FUNC_ARG;
}
/* verify input cannot exceed buffer */
if (digestSz > (int)sizeof(verifySigIn.digest.buffer))
digestSz = (int)sizeof(verifySigIn.digest.buffer);
/* set session auth for key */
wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
XMEMSET(&verifySigIn, 0, sizeof(verifySigIn));
verifySigIn.keyHandle = key->handle.hndl;
verifySigIn.digest.size = digestSz;
XMEMCPY(verifySigIn.digest.buffer, digest, digestSz);
verifySigIn.signature.sigAlg = sigAlg;
verifySigIn.signature.signature.any.hashAlg = hashAlg;
if (key->pub.publicArea.type == TPM_ALG_ECC) {
/* Signature is R then S */
verifySigIn.signature.signature.ecdsa.signatureR.size = curveSize;
XMEMCPY(verifySigIn.signature.signature.ecdsa.signatureR.buffer,
sig, curveSize);
verifySigIn.signature.signature.ecdsa.signatureS.size = curveSize;
XMEMCPY(verifySigIn.signature.signature.ecdsa.signatureS.buffer,
sig + curveSize, curveSize);
}
else if (key->pub.publicArea.type == TPM_ALG_RSA) {
verifySigIn.signature.signature.rsassa.sig.size = sigSz;
XMEMCPY(verifySigIn.signature.signature.rsassa.sig.buffer, sig, sigSz);
}
XMEMSET(&verifySigOut, 0, sizeof(verifySigOut));
rc = TPM2_VerifySignature(&verifySigIn, &verifySigOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_VerifySignature failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
}
else {
/* optionally return ticket */
if (checkTicket) {
XMEMCPY(checkTicket, &verifySigOut.validation,
sizeof(TPMT_TK_VERIFIED));
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_VerifySignature: Tag %d\n", verifySigOut.validation.tag);
#endif
}
return rc;
}
int wolfTPM2_VerifyHashScheme(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
const byte* sig, int sigSz, const byte* digest, int digestSz,
TPMI_ALG_SIG_SCHEME sigAlg, TPMI_ALG_HASH hashAlg)
{
return wolfTPM2_VerifyHashTicket(dev, key, sig, sigSz, digest,
digestSz, sigAlg, hashAlg, NULL);
}
int wolfTPM2_VerifyHash_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
const byte* sig, int sigSz, const byte* digest, int digestSz,
int hashAlg)
{
return wolfTPM2_VerifyHashTicket(dev, key, sig, sigSz, digest,
digestSz, TPM_ALG_NULL, hashAlg, NULL);
}
int wolfTPM2_VerifyHash(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
const byte* sig, int sigSz, const byte* digest, int digestSz)
{
return wolfTPM2_VerifyHashTicket(dev, key, sig, sigSz, digest, digestSz,
TPM_ALG_NULL, WOLFTPM2_WRAP_DIGEST, NULL);
}
/* Generate ECC key-pair with NULL hierarchy and load (populates handle) */
int wolfTPM2_ECDHGenKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* ecdhKey, int curve_id,
const byte* auth, int authSz)
{
int rc;
TPMT_PUBLIC publicTemplate;
WOLFTPM2_HANDLE nullParent;
if (dev == NULL || ecdhKey == NULL) {
return BAD_FUNC_ARG;
}
XMEMSET(&nullParent, 0, sizeof(nullParent));
nullParent.hndl = TPM_RH_NULL;
/* Create and load ECC key for DH */
rc = wolfTPM2_GetKeyTemplate_ECC(&publicTemplate,
TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
TPMA_OBJECT_decrypt | TPMA_OBJECT_noDA,
curve_id, TPM_ALG_ECDH);
if (rc == 0) {
rc = wolfTPM2_CreatePrimaryKey(dev, ecdhKey, TPM_RH_NULL,
&publicTemplate, auth, authSz);
}
return rc;
}
/* Generate ephemeral key and compute Z (shared secret) */
/* One shot API using private key handle to generate key-pair and return
pub-point and shared secret */
int wolfTPM2_ECDHGen(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* privKey,
TPM2B_ECC_POINT* pubPoint, byte* out, int* outSz)
{
int rc;
ECDH_KeyGen_In ecdhIn;
ECDH_KeyGen_Out ecdhOut;
int curveSize;
if (dev == NULL || privKey == NULL || pubPoint == NULL || out == NULL ||
outSz == NULL) {
return BAD_FUNC_ARG;
}
/* get curve size to verify output is large enough */
curveSize = wolfTPM2_GetCurveSize(
privKey->pub.publicArea.parameters.eccDetail.curveID);
if (curveSize <= 0 || *outSz < curveSize) {
return BAD_FUNC_ARG;
}
/* set session auth for key */
wolfTPM2_SetAuthHandle(dev, 0, &privKey->handle);
XMEMSET(&ecdhIn, 0, sizeof(ecdhIn));
ecdhIn.keyHandle = privKey->handle.hndl;
rc = TPM2_ECDH_KeyGen(&ecdhIn, &ecdhOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_ECDH_KeyGen failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
pubPoint->size = ecdhOut.pubPoint.size;
wolfTPM2_CopyEccParam(&pubPoint->point.x, &ecdhOut.pubPoint.point.x);
wolfTPM2_CopyEccParam(&pubPoint->point.y, &ecdhOut.pubPoint.point.y);
*outSz = ecdhOut.zPoint.point.x.size;
XMEMCPY(out, ecdhOut.zPoint.point.x.buffer, ecdhOut.zPoint.point.x.size);
#ifdef DEBUG_WOLFTPM
printf("TPM2_ECDH_KeyGen: zPt %d, pubPt %d\n",
ecdhOut.zPoint.size,
ecdhOut.pubPoint.size);
#endif
return rc;
}
/* Compute Z (shared secret) using pubPoint and loaded private ECC key */
int wolfTPM2_ECDHGenZ(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* privKey,
const TPM2B_ECC_POINT* pubPoint, byte* out, int* outSz)
{
int rc;
ECDH_ZGen_In ecdhZIn;
ECDH_ZGen_Out ecdhZOut;
int curveSize;
if (dev == NULL || privKey == NULL || pubPoint == NULL || out == NULL ||
outSz == NULL) {
return BAD_FUNC_ARG;
}
/* get curve size to verify output is large enough */
curveSize = wolfTPM2_GetCurveSize(
privKey->pub.publicArea.parameters.eccDetail.curveID);
if (curveSize <= 0 || *outSz < curveSize) {
return BAD_FUNC_ARG;
}
/* set session auth for key */
wolfTPM2_SetAuthHandle(dev, 0, &privKey->handle);
XMEMSET(&ecdhZIn, 0, sizeof(ecdhZIn));
ecdhZIn.keyHandle = privKey->handle.hndl;
XMEMCPY(&ecdhZIn.inPoint.point, &pubPoint->point, sizeof(TPMS_ECC_POINT));
rc = TPM2_ECDH_ZGen(&ecdhZIn, &ecdhZOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_ECDH_ZGen failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
*outSz = ecdhZOut.outPoint.point.x.size;
XMEMCPY(out, ecdhZOut.outPoint.point.x.buffer,
ecdhZOut.outPoint.point.x.size);
#ifdef DEBUG_WOLFTPM
printf("TPM2_ECDH_ZGen: zPt %d\n", ecdhZOut.outPoint.size);
#endif
return rc;
}
/* Generate ephemeral ECC key and return array index (2 phase method) */
/* One time use key */
int wolfTPM2_ECDHEGenKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* ecdhKey, int curve_id)
{
int rc;
EC_Ephemeral_In in;
EC_Ephemeral_Out out;
if (dev == NULL || ecdhKey == NULL) {
return BAD_FUNC_ARG;
}
XMEMSET(&in, 0, sizeof(in));
in.curveID = curve_id;
rc = TPM2_EC_Ephemeral(&in, &out);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_EC_Ephemeral failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
/* Save the point and counter (commit ID) into ecdhKey */
wolfTPM2_CopyEccParam(&ecdhKey->pub.publicArea.unique.ecc.x, &out.Q.point.x);
wolfTPM2_CopyEccParam(&ecdhKey->pub.publicArea.unique.ecc.y, &out.Q.point.y);
ecdhKey->handle.hndl = (UINT32)out.counter;
return rc;
}
/* Compute Z (shared secret) using pubPoint and counter (2 phase method) */
/* The counter / array ID can only be used one time */
int wolfTPM2_ECDHEGenZ(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* parentKey,
WOLFTPM2_KEY* ecdhKey, const TPM2B_ECC_POINT* pubPoint,
byte* out, int* outSz)
{
int rc;
ZGen_2Phase_In inZGen2Ph;
ZGen_2Phase_Out outZGen2Ph;
int curveSize;
if (dev == NULL || parentKey == NULL || ecdhKey == NULL ||
pubPoint == NULL || out == NULL || outSz == NULL) {
return BAD_FUNC_ARG;
}
/* get curve size to verify output is large enough */
curveSize = wolfTPM2_GetCurveSize(
parentKey->pub.publicArea.parameters.eccDetail.curveID);
if (curveSize <= 0 || *outSz < curveSize) {
return BAD_FUNC_ARG;
}
/* set session auth for key */
wolfTPM2_SetAuthHandle(dev, 0, &parentKey->handle);
XMEMSET(&inZGen2Ph, 0, sizeof(inZGen2Ph));
inZGen2Ph.keyA = ecdhKey->handle.hndl;
ecdhKey->handle.hndl = TPM_RH_NULL;
XMEMCPY(&inZGen2Ph.inQsB.point, &pubPoint->point, sizeof(TPMS_ECC_POINT));
XMEMCPY(&inZGen2Ph.inQeB.point, &pubPoint->point, sizeof(TPMS_ECC_POINT));
inZGen2Ph.inScheme = TPM_ALG_ECDH;
inZGen2Ph.counter = (UINT16)ecdhKey->handle.hndl;
rc = TPM2_ZGen_2Phase(&inZGen2Ph, &outZGen2Ph);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_ZGen_2Phase failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
*outSz = outZGen2Ph.outZ2.point.x.size;
XMEMCPY(out, outZGen2Ph.outZ2.point.x.buffer,
outZGen2Ph.outZ2.point.x.size);
#ifdef DEBUG_WOLFTPM
printf("TPM2_ZGen_2Phase: zPt %d\n", outZGen2Ph.outZ2.size);
#endif
return rc;
}
int wolfTPM2_RsaEncrypt(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
TPM_ALG_ID padScheme, const byte* msg, int msgSz, byte* out, int* outSz)
{
int rc;
RSA_Encrypt_In rsaEncIn;
RSA_Encrypt_Out rsaEncOut;
if (dev == NULL || key == NULL || msg == NULL || out == NULL ||
outSz == NULL) {
return BAD_FUNC_ARG;
}
/* set session auth for key */
wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
/* RSA Encrypt */
XMEMSET(&rsaEncIn, 0, sizeof(rsaEncIn));
rsaEncIn.keyHandle = key->handle.hndl;
rsaEncIn.message.size = msgSz;
XMEMCPY(rsaEncIn.message.buffer, msg, msgSz);
/* TPM_ALG_NULL, TPM_ALG_OAEP, TPM_ALG_RSASSA or TPM_ALG_RSAPSS */
rsaEncIn.inScheme.scheme = padScheme;
rsaEncIn.inScheme.details.anySig.hashAlg = WOLFTPM2_WRAP_DIGEST;
#if 0
/* Optional label */
rsaEncIn.label.size = sizeof(label); /* Null term required */
XMEMCPY(rsaEncIn.label.buffer, label, rsaEncIn.label.size);
#endif
rc = TPM2_RSA_Encrypt(&rsaEncIn, &rsaEncOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_RSA_Encrypt failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
*outSz = rsaEncOut.outData.size;
XMEMCPY(out, rsaEncOut.outData.buffer, *outSz);
#ifdef DEBUG_WOLFTPM
printf("TPM2_RSA_Encrypt: %d\n", rsaEncOut.outData.size);
#endif
return rc;
}
int wolfTPM2_RsaDecrypt(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
TPM_ALG_ID padScheme, const byte* in, int inSz, byte* msg, int* msgSz)
{
int rc;
RSA_Decrypt_In rsaDecIn;
RSA_Decrypt_Out rsaDecOut;
if (dev == NULL || key == NULL || in == NULL || msg == NULL ||
msgSz == NULL) {
return BAD_FUNC_ARG;
}
/* set session auth and name for key */
wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
/* RSA Decrypt */
XMEMSET(&rsaDecIn, 0, sizeof(rsaDecIn));
rsaDecIn.keyHandle = key->handle.hndl;
rsaDecIn.cipherText.size = inSz;
XMEMCPY(rsaDecIn.cipherText.buffer, in, inSz);
/* TPM_ALG_NULL, TPM_ALG_OAEP, TPM_ALG_RSASSA or TPM_ALG_RSAPSS */
rsaDecIn.inScheme.scheme = padScheme;
rsaDecIn.inScheme.details.anySig.hashAlg = WOLFTPM2_WRAP_DIGEST;
#if 0
/* Optional label */
rsaDecIn.label.size = sizeof(label); /* Null term required */
XMEMCPY(rsaDecIn.label.buffer, label, rsaEncIn.label.size);
#endif
rc = TPM2_RSA_Decrypt(&rsaDecIn, &rsaDecOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_RSA_Decrypt failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
*msgSz = rsaDecOut.message.size;
XMEMCPY(msg, rsaDecOut.message.buffer, *msgSz);
#ifdef DEBUG_WOLFTPM
printf("TPM2_RSA_Decrypt: %d\n", rsaDecOut.message.size);
#endif
return rc;
}
int wolfTPM2_ResetPCR(WOLFTPM2_DEV* dev, int pcrIndex)
{
int rc;
PCR_Reset_In pcrReset;
XMEMSET(&pcrReset, 0, sizeof(pcrReset));
pcrReset.pcrHandle = pcrIndex;
rc = TPM2_PCR_Reset(&pcrReset);
(void)dev;
return rc;
}
/* TODO: Version that can read up to 8 PCR's at a time */
int wolfTPM2_ReadPCR(WOLFTPM2_DEV* dev, int pcrIndex, int hashAlg, byte* digest,
int* pDigestLen)
{
int rc;
PCR_Read_In pcrReadIn;
PCR_Read_Out pcrReadOut;
int digestLen = 0;
if (dev == NULL || pcrIndex < (int)PCR_FIRST || pcrIndex > (int)PCR_LAST)
return BAD_FUNC_ARG;
/* set session auth to blank */
if (dev->ctx.session) {
wolfTPM2_SetAuthPassword(dev, 0, NULL);
}
XMEMSET(&pcrReadIn, 0, sizeof(pcrReadIn));
wolfTPM2_SetupPCRSel(&pcrReadIn.pcrSelectionIn, hashAlg, pcrIndex);
rc = TPM2_PCR_Read(&pcrReadIn, &pcrReadOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_PCR_Read failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
#endif
return rc;
}
digestLen = (int)pcrReadOut.pcrValues.digests[0].size;
if (digest)
XMEMCPY(digest, pcrReadOut.pcrValues.digests[0].buffer, digestLen);
#ifdef DEBUG_WOLFTPM
printf("TPM2_PCR_Read: Index %d, Digest Sz %d, Update Counter %d\n",
pcrIndex, digestLen, (int)pcrReadOut.pcrUpdateCounter);
TPM2_PrintBin(digest, digestLen);
#endif
if (pDigestLen)
*pDigestLen = digestLen;
return rc;
}
int wolfTPM2_ExtendPCR(WOLFTPM2_DEV* dev, int pcrIndex, int hashAlg,
const byte* digest, int digestLen)
{
int rc;
PCR_Extend_In pcrExtend;
if (dev == NULL || digestLen > TPM_MAX_DIGEST_SIZE) {
return BAD_FUNC_ARG;
}
/* set session auth to blank */
if (dev->ctx.session) {
wolfTPM2_SetAuthPassword(dev, 0, NULL);
}
XMEMSET(&pcrExtend, 0, sizeof(pcrExtend));
pcrExtend.pcrHandle = pcrIndex;
pcrExtend.digests.count = 1;
pcrExtend.digests.digests[0].hashAlg = hashAlg;
XMEMCPY(pcrExtend.digests.digests[0].digest.H, digest, digestLen);
rc = TPM2_PCR_Extend(&pcrExtend);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_PCR_Extend failed 0x%x: %s\n", rc, TPM2_GetRCString(rc));
#endif
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_PCR_Extend: Index %d, Digest Sz %d\n", pcrIndex, digestLen);
#endif
return rc;
}
int wolfTPM2_UnloadHandle(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* handle)
{
int rc;
FlushContext_In in;
if (dev == NULL || handle == NULL)
return BAD_FUNC_ARG;
/* don't try and unload null or persistent handles */
if (handle->hndl == 0 || handle->hndl == TPM_RH_NULL ||
(handle->hndl >= PERSISTENT_FIRST && handle->hndl <= PERSISTENT_LAST)) {
return TPM_RC_SUCCESS;
}
XMEMSET(&in, 0, sizeof(in));
in.flushHandle = handle->hndl;
rc = TPM2_FlushContext(&in);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_FlushContext failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_FlushContext: Closed handle 0x%x\n", (word32)handle->hndl);
#endif
handle->hndl = TPM_RH_NULL;
return TPM_RC_SUCCESS;
}
/* nv is the populated handle and auth */
/* auth and authSz are optional NV authentication */
int wolfTPM2_NVCreateAuth(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
WOLFTPM2_NV* nv, word32 nvIndex, word32 nvAttributes, word32 maxSize,
const byte* auth, int authSz)
{
int rc, rctmp, alreadyExists = 0;
NV_DefineSpace_In in;
if (dev == NULL || nv == NULL) {
return BAD_FUNC_ARG;
}
/* set session auth for key */
rc = wolfTPM2_SetAuthHandle(dev, 0, parent);
if (rc != TPM_RC_SUCCESS) { return rc; }
XMEMSET(&in, 0, sizeof(in));
in.authHandle = parent->hndl;
if (auth && authSz > 0) {
if (authSz > (int)sizeof(in.auth.buffer))
authSz = (int)sizeof(in.auth.buffer);
in.auth.size = authSz;
XMEMCPY(in.auth.buffer, auth, in.auth.size);
}
in.publicInfo.nvPublic.nvIndex = nvIndex;
in.publicInfo.nvPublic.nameAlg = WOLFTPM2_WRAP_DIGEST;
in.publicInfo.nvPublic.attributes = nvAttributes;
in.publicInfo.nvPublic.dataSize = (UINT16)maxSize;
rc = TPM2_NV_DefineSpace(&in);
if (rc == TPM_RC_NV_DEFINED) {
alreadyExists = 1;
#ifdef DEBUG_WOLFTPM
printf("TPM2_NV_DefineSpace: handle already exists\n");
#endif
}
else if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_NV_DefineSpace failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
if (rc == TPM_RC_SUCCESS && alreadyExists)
rc = TPM_RC_NV_DEFINED;
/* compute NV object with name */
XMEMSET(nv, 0, sizeof(*nv));
rctmp = wolfTPM2_NVOpen(dev, nv, nvIndex, auth, authSz);
if (rctmp != TPM_RC_SUCCESS)
rc = rctmp;
#ifdef DEBUG_WOLFTPM
printf("TPM2_NV_DefineSpace: Auth 0x%x, Idx 0x%x, Attribs 0x%d, Size %d\n",
(word32)in.authHandle,
(word32)in.publicInfo.nvPublic.nvIndex,
(word32)in.publicInfo.nvPublic.attributes,
in.publicInfo.nvPublic.dataSize);
#endif
/* if handle already existed then return `TPM_RC_NV_DEFINED` */
return (rc == TPM_RC_SUCCESS && alreadyExists) ? TPM_RC_NV_DEFINED : rc;
}
/* older API kept for compatibility, recommend using wolfTPM2_NVCreateAuth */
int wolfTPM2_NVCreate(WOLFTPM2_DEV* dev, TPM_HANDLE authHandle,
word32 nvIndex, word32 nvAttributes, word32 maxSize,
const byte* auth, int authSz)
{
WOLFTPM2_NV nv;
WOLFTPM2_HANDLE parent;
XMEMSET(&nv, 0, sizeof(nv));
XMEMSET(&parent, 0, sizeof(parent));
parent.hndl = authHandle;
return wolfTPM2_NVCreateAuth(dev, &parent, &nv, nvIndex, nvAttributes,
maxSize, auth, authSz);
}
int wolfTPM2_NVWriteAuth(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv,
word32 nvIndex, byte* dataBuf, word32 dataSz, word32 offset)
{
int rc = TPM_RC_SUCCESS;
word32 pos = 0, towrite;
NV_Write_In in;
if (dev == NULL || nv == NULL) {
return BAD_FUNC_ARG;
}
/* make sure the name is computed for the handle */
if (!nv->handle.nameLoaded) {
rc = wolfTPM2_NVOpen(dev, nv, nvIndex, NULL, 0);
if (rc != 0) {
return rc;
}
}
/* Necessary, because NVWrite has two handles, second is NV Index */
rc = wolfTPM2_SetAuthHandleName(dev, 0, &nv->handle);
rc |= wolfTPM2_SetAuthHandleName(dev, 1, &nv->handle);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("Setting NV index name failed\n");
#endif
return TPM_RC_FAILURE;
}
while (dataSz > 0) {
towrite = dataSz;
if (towrite > MAX_NV_BUFFER_SIZE)
towrite = MAX_NV_BUFFER_SIZE;
XMEMSET(&in, 0, sizeof(in));
in.authHandle = nv->handle.hndl;
in.nvIndex = nvIndex;
in.offset = offset+pos;
in.data.size = towrite;
if (dataBuf)
XMEMCPY(in.data.buffer, &dataBuf[pos], towrite);
rc = TPM2_NV_Write(&in);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_NV_Write failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
/* if this is the first write to NV then the NV_WRITTEN bit will get set
* and name needs re-computed */
if (pos == 0) {
/* read public and re-compute name */
rc = wolfTPM2_NVOpen(dev, nv, nv->handle.hndl, NULL, 0);
if (rc != 0) break;
}
#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);
#endif
pos += towrite;
dataSz -= towrite;
}
return rc;
}
/* older API kept for compatibility, recommend using wolfTPM2_NVWriteAuth */
int wolfTPM2_NVWrite(WOLFTPM2_DEV* dev, TPM_HANDLE authHandle,
word32 nvIndex, byte* dataBuf, word32 dataSz, word32 offset)
{
WOLFTPM2_NV nv;
XMEMSET(&nv, 0, sizeof(nv));
nv.handle.hndl = (TPM_HANDLE)nvIndex;
(void)authHandle;
return wolfTPM2_NVWriteAuth(dev, &nv, nvIndex, dataBuf, dataSz, offset);
}
int wolfTPM2_NVReadAuth(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv,
word32 nvIndex, byte* dataBuf, word32* pDataSz, word32 offset)
{
int rc = TPM_RC_SUCCESS;
word32 pos = 0, toread, dataSz;
NV_Read_In in;
NV_Read_Out out;
if (dev == NULL || nv == NULL || pDataSz == NULL) {
return BAD_FUNC_ARG;
}
/* make sure the name is computed for the handle */
if (!nv->handle.nameLoaded) {
rc = wolfTPM2_NVOpen(dev, nv, nvIndex, NULL, 0);
if (rc != TPM_RC_SUCCESS) { return rc; }
}
/* Necessary, because NVRead has two handles, second is NV Index */
rc = wolfTPM2_SetAuthHandleName(dev, 0, &nv->handle);
rc |= wolfTPM2_SetAuthHandleName(dev, 1, &nv->handle);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("Setting NV index name failed\n");
#endif
return TPM_RC_FAILURE;
}
dataSz = *pDataSz;
while (dataSz > 0) {
toread = dataSz;
if (toread > MAX_NV_BUFFER_SIZE)
toread = MAX_NV_BUFFER_SIZE;
XMEMSET(&in, 0, sizeof(in));
in.authHandle = nv->handle.hndl;
in.nvIndex = nvIndex;
in.offset = offset+pos;
in.size = toread;
rc = TPM2_NV_Read(&in, &out);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_NV_Read failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
toread = out.data.size;
if (dataBuf) {
XMEMCPY(&dataBuf[pos], out.data.buffer, toread);
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_NV_Read: Auth 0x%x, Idx 0x%x, Offset %d, Size %d\n",
(word32)in.authHandle, (word32)in.nvIndex, in.offset, out.data.size);
#endif
/* if we are done reading, exit loop */
if (toread == 0)
break;
pos += toread;
dataSz -= toread;
}
*pDataSz = pos;
return rc;
}
/* older API kept for compatibility, recommend using wolfTPM2_NVReadAuth */
int wolfTPM2_NVRead(WOLFTPM2_DEV* dev, TPM_HANDLE authHandle,
word32 nvIndex, byte* dataBuf, word32* pDataSz, word32 offset)
{
WOLFTPM2_NV nv;
XMEMSET(&nv, 0, sizeof(nv));
nv.handle.hndl = (TPM_HANDLE)nvIndex;
(void)authHandle;
return wolfTPM2_NVReadAuth(dev, &nv, nvIndex, dataBuf, pDataSz, offset);
}
int wolfTPM2_NVOpen(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv, word32 nvIndex,
const byte* auth, word32 authSz)
{
int rc = TPM_RC_SUCCESS;
TPMS_NV_PUBLIC nvPublic;
if (dev == NULL || nv == NULL || authSz > sizeof(nv->handle.auth.buffer)) {
return BAD_FUNC_ARG;
}
/* build the "handle" */
nv->handle.hndl = nvIndex;
/* auth can also be set already via nv->handle */
if (auth != NULL && authSz > 0) {
nv->handle.auth.size = authSz;
XMEMCPY(nv->handle.auth.buffer, auth, authSz);
}
/* Read the NV Index publicArea to have up to date NV Index Name */
rc = wolfTPM2_NVReadPublic(dev, nv->handle.hndl, &nvPublic);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("Failed to open (read) NV\n");
#endif
return rc;
}
/* Compute NV Index name in case of parameter encryption */
#ifndef WOLFTPM2_NO_WOLFCRYPT
rc = TPM2_HashNvPublic(&nvPublic, (byte*)&nv->handle.name.name,
&nv->handle.name.size);
if (rc != TPM_RC_SUCCESS) {
return rc;
}
#endif
/* flag that the NV was "opened" and name was loaded */
nv->handle.nameLoaded = 1;
return rc;
}
int wolfTPM2_NVReadPublic(WOLFTPM2_DEV* dev, word32 nvIndex,
TPMS_NV_PUBLIC* nvPublic)
{
int rc;
NV_ReadPublic_In in;
NV_ReadPublic_Out out;
if (dev == NULL) {
return BAD_FUNC_ARG;
}
XMEMSET(&in, 0, sizeof(in));
in.nvIndex = nvIndex;
rc = TPM2_NV_ReadPublic(&in, &out);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_NV_ReadPublic failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_NV_ReadPublic: Sz %d, Idx 0x%x, nameAlg %d, Attr 0x%x, "
"authPol %d, dataSz %d, name %d\n",
out.nvPublic.size,
(word32)out.nvPublic.nvPublic.nvIndex,
out.nvPublic.nvPublic.nameAlg,
(word32)out.nvPublic.nvPublic.attributes,
out.nvPublic.nvPublic.authPolicy.size,
out.nvPublic.nvPublic.dataSize,
out.nvName.size);
#endif
if (nvPublic) {
wolfTPM2_CopyNvPublic(nvPublic, &out.nvPublic.nvPublic);
}
return rc;
}
int wolfTPM2_NVIncrement(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv)
{
int rc = TPM_RC_SUCCESS;
NV_Increment_In in;
if (dev == NULL || nv == NULL) {
return BAD_FUNC_ARG;
}
/* make sure the name is computed for the handle */
if (!nv->handle.nameLoaded) {
rc = wolfTPM2_NVOpen(dev, nv, nv->handle.hndl, NULL, 0);
if (rc != TPM_RC_SUCCESS) { return rc; }
}
/* Necessary, because NVRead has two handles, second is NV Index */
rc = wolfTPM2_SetAuthHandleName(dev, 0, &nv->handle);
rc |= wolfTPM2_SetAuthHandleName(dev, 1, &nv->handle);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("Setting NV index name failed\n");
#endif
return rc;
}
XMEMSET(&in, 0, sizeof(in));
in.authHandle = nv->handle.hndl;
in.nvIndex = nv->handle.hndl;
#ifdef DEBUG_WOLFTPM
printf("TPM2_NV_Increment: Auth 0x%x, Idx 0x%x\n",
(word32)in.authHandle, (word32)in.nvIndex);
#endif
rc = TPM2_NV_Increment(&in);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_NV_Increment failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
return rc;
}
int wolfTPM2_NVWriteLock(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv)
{
int rc;
NV_WriteLock_In in;
if (dev == NULL || nv == NULL) {
return BAD_FUNC_ARG;
}
/* make sure the name is computed for the handle */
if (!nv->handle.nameLoaded) {
rc = wolfTPM2_NVOpen(dev, nv, nv->handle.hndl, NULL, 0);
if (rc != 0) {
return rc;
}
}
/* Necessary, because NVRead has two handles, second is NV Index */
rc = wolfTPM2_SetAuthHandleName(dev, 0, &nv->handle);
rc |= wolfTPM2_SetAuthHandleName(dev, 1, &nv->handle);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("Setting NV index name failed\n");
#endif
return TPM_RC_FAILURE;
}
XMEMSET(&in, 0, sizeof(in));
in.authHandle = nv->handle.hndl;
in.nvIndex = nv->handle.hndl;
return TPM2_NV_WriteLock(&in);
}
int wolfTPM2_NVDeleteAuth(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
word32 nvIndex)
{
int rc;
NV_UndefineSpace_In in;
if (dev == NULL || parent == NULL) {
return BAD_FUNC_ARG;
}
/* set session auth for key */
if (dev->ctx.session) {
rc = wolfTPM2_SetAuthHandle(dev, 0, parent);
if (rc != TPM_RC_SUCCESS) { return rc; }
}
XMEMSET(&in, 0, sizeof(in));
in.authHandle = parent->hndl;
in.nvIndex = nvIndex;
rc = TPM2_NV_UndefineSpace(&in);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_NV_UndefineSpace failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_NV_UndefineSpace: Auth 0x%x, Idx 0x%x\n",
(word32)in.authHandle, (word32)in.nvIndex);
#endif
return rc;
}
/* older API kept for compatibility, recommend using wolfTPM2_NVDeleteAuth */
int wolfTPM2_NVDelete(WOLFTPM2_DEV* dev, TPM_HANDLE authHandle,
word32 nvIndex)
{
WOLFTPM2_HANDLE parent;
XMEMSET(&parent, 0, sizeof(parent));
parent.hndl = authHandle;
return wolfTPM2_NVDeleteAuth(dev, &parent, nvIndex);
}
#ifndef WOLFTPM2_NO_WOLFCRYPT
struct WC_RNG* wolfTPM2_GetRng(WOLFTPM2_DEV* dev)
{
WC_RNG* rng = NULL;
if (dev) {
#ifdef WOLFTPM2_USE_WOLF_RNG
(void)TPM2_GetWolfRng(&rng);
#endif
}
return rng;
}
#endif
int wolfTPM2_GetRandom(WOLFTPM2_DEV* dev, byte* buf, word32 len)
{
int rc = TPM_RC_SUCCESS;
GetRandom_In in;
GetRandom_Out out;
word32 sz, pos = 0;
if (dev == NULL || buf == NULL)
return BAD_FUNC_ARG;
while (pos < len) {
/* calculate size to get */
sz = len - pos;
if (sz > MAX_RNG_REQ_SIZE)
sz = MAX_RNG_REQ_SIZE;
XMEMSET(&in, 0, sizeof(in));
in.bytesRequested = sz;
rc = TPM2_GetRandom(&in, &out);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_GetRandom failed 0x%x: %s\n", rc,
TPM2_GetRCString(rc));
#endif
break;
}
sz = out.randomBytes.size; /* use actual returned size */
if (sz > MAX_RNG_REQ_SIZE) {
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_GetRandom out size error\n");
#endif
rc = BAD_FUNC_ARG;
break;
}
XMEMCPY(&buf[pos], out.randomBytes.buffer, sz);
pos += sz;
}
return rc;
}
int wolfTPM2_Clear(WOLFTPM2_DEV* dev)
{
int rc;
Clear_In in;
if (dev == NULL)
return BAD_FUNC_ARG;
XMEMSET(&in, 0, sizeof(in));
in.authHandle = TPM_RH_LOCKOUT;
rc = TPM2_Clear(&in);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_Clear failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
return rc;
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_Clear Auth 0x%x\n", (word32)in.authHandle);
#endif
return rc;
}
/* Hashing */
/* usageAuth: Optional auth for handle */
int wolfTPM2_HashStart(WOLFTPM2_DEV* dev, WOLFTPM2_HASH* hash,
TPMI_ALG_HASH hashAlg, const byte* usageAuth, word32 usageAuthSz)
{
int rc;
HashSequenceStart_In in;
HashSequenceStart_Out out;
if (dev == NULL || hash == NULL || hashAlg == TPM_ALG_NULL ||
(usageAuthSz > 0 && usageAuth == NULL)) {
return BAD_FUNC_ARG;
}
/* Capture usage auth */
if (usageAuthSz > sizeof(hash->handle.auth.buffer))
usageAuthSz = sizeof(hash->handle.auth.buffer);
XMEMSET(hash, 0, sizeof(WOLFTPM2_HASH));
hash->handle.auth.size = usageAuthSz;
if (usageAuth != NULL)
XMEMCPY(hash->handle.auth.buffer, usageAuth, usageAuthSz);
XMEMSET(&in, 0, sizeof(in));
wolfTPM2_CopyAuth(&in.auth, &hash->handle.auth);
in.hashAlg = hashAlg;
rc = TPM2_HashSequenceStart(&in, &out);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_HashSequenceStart failed 0x%x: %s\n", rc,
TPM2_GetRCString(rc));
#endif
return rc;
}
/* Capture hash sequence handle */
hash->handle.hndl = out.sequenceHandle;
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_HashStart: Handle 0x%x\n",
(word32)out.sequenceHandle);
#endif
return rc;
}
int wolfTPM2_HashUpdate(WOLFTPM2_DEV* dev, WOLFTPM2_HASH* hash,
const byte* data, word32 dataSz)
{
int rc = TPM_RC_SUCCESS;
SequenceUpdate_In in;
word32 pos = 0, hashSz;
if (dev == NULL || hash == NULL || (data == NULL && dataSz > 0) ||
hash->handle.hndl == 0) {
return BAD_FUNC_ARG;
}
/* set session auth for hash handle */
wolfTPM2_SetAuthHandle(dev, 0, &hash->handle);
XMEMSET(&in, 0, sizeof(in));
in.sequenceHandle = hash->handle.hndl;
while (pos < dataSz) {
hashSz = dataSz - pos;
if (hashSz > sizeof(in.buffer.buffer))
hashSz = sizeof(in.buffer.buffer);
in.buffer.size = hashSz;
XMEMCPY(in.buffer.buffer, &data[pos], hashSz);
rc = TPM2_SequenceUpdate(&in);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_SequenceUpdate failed 0x%x: %s\n", rc,
TPM2_GetRCString(rc));
#endif
return rc;
}
pos += hashSz;
}
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_HashUpdate: Handle 0x%x, DataSz %d\n",
(word32)in.sequenceHandle, dataSz);
#endif
return rc;
}
int wolfTPM2_HashFinish(WOLFTPM2_DEV* dev, WOLFTPM2_HASH* hash,
byte* digest, word32* digestSz)
{
int rc;
SequenceComplete_In in;
SequenceComplete_Out out;
if (dev == NULL || hash == NULL || digest == NULL || digestSz == NULL ||
hash->handle.hndl == 0) {
return BAD_FUNC_ARG;
}
/* set session auth for hash handle */
wolfTPM2_SetAuthHandle(dev, 0, &hash->handle);
XMEMSET(&in, 0, sizeof(in));
in.sequenceHandle = hash->handle.hndl;
in.hierarchy = TPM_RH_NULL;
rc = TPM2_SequenceComplete(&in, &out);
/* mark hash handle as done */
hash->handle.hndl = TPM_RH_NULL;
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_SequenceComplete failed 0x%x: %s: Handle 0x%x\n", rc,
TPM2_GetRCString(rc), (word32)in.sequenceHandle);
#endif
return rc;
}
if (out.result.size > *digestSz)
out.result.size = *digestSz;
*digestSz = out.result.size;
XMEMCPY(digest, out.result.buffer, *digestSz);
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_HashFinish: Handle 0x%x, DigestSz %d\n",
(word32)in.sequenceHandle, *digestSz);
#endif
return rc;
}
static int wolfTPM2_ComputeSymmetricUnique(WOLFTPM2_DEV* dev, int hashAlg,
const TPMT_SENSITIVE* sensitive, TPM2B_DIGEST* unique)
{
int rc;
#ifdef WOLFTPM_USE_SYMMETRIC
WOLFTPM2_HASH hash;
#elif !defined(WOLFTPM2_NO_WOLFCRYPT)
wc_HashAlg hash;
enum wc_HashType hashType;
int hashSz;
#endif
if (dev == NULL || sensitive == NULL || unique == NULL) {
return BAD_FUNC_ARG;
}
#ifdef WOLFTPM_USE_SYMMETRIC
rc = wolfTPM2_HashStart(dev, &hash, hashAlg, NULL, 0);
if (rc == 0) {
/* sensitive seed */
rc = wolfTPM2_HashUpdate(dev, &hash, sensitive->seedValue.buffer,
sensitive->seedValue.size);
if (rc == 0) {
/* sensitive value */
rc = wolfTPM2_HashUpdate(dev, &hash, sensitive->sensitive.any.buffer,
sensitive->sensitive.any.size);
}
if (rc == 0) {
word32 uniqueSz = TPM2_GetHashDigestSize(hashAlg);
rc = wolfTPM2_HashFinish(dev, &hash, unique->buffer, &uniqueSz);
unique->size = uniqueSz;
}
else {
/* Make sure hash if free'd on failure */
wolfTPM2_UnloadHandle(dev, &hash.handle);
}
}
#elif !defined(WOLFTPM2_NO_WOLFCRYPT)
rc = TPM2_GetHashType(hashAlg);
hashType = (enum wc_HashType)rc;
rc = wc_HashGetDigestSize(hashType);
if (rc < 0)
return rc;
hashSz = rc;
/* Hash of data (name) goes into remainder */
rc = wc_HashInit(&hash, hashType);
if (rc == 0) {
/* sensitive seed */
rc = wc_HashUpdate(&hash, hashType, sensitive->seedValue.buffer,
sensitive->seedValue.size);
if (rc == 0) {
/* sensitive value */
rc = wc_HashUpdate(&hash, hashType, sensitive->sensitive.any.buffer,
sensitive->sensitive.any.size);
}
if (rc == 0) {
rc = wc_HashFinal(&hash, hashType, unique->buffer);
if (rc == 0)
unique->size = hashSz;
}
wc_HashFree(&hash, hashType);
}
#else
(void)hashAlg;
rc = NOT_COMPILED_IN;
#endif
return rc;
}
int wolfTPM2_LoadSymmetricKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, int alg,
const byte* keyBuf, word32 keySz)
{
int rc;
LoadExternal_In loadExtIn;
LoadExternal_Out loadExtOut;
int hashAlg, hashAlgDigSz;
if (dev == NULL || key == NULL || keyBuf == NULL ||
(keySz != 16 && keySz != 32)) {
return BAD_FUNC_ARG;
}
if (keySz > sizeof(loadExtIn.inPrivate.sensitiveArea.sensitive.sym.buffer)) {
return BUFFER_E;
}
hashAlg = (keySz == 32) ? TPM_ALG_SHA256 : TPM_ALG_SHA1;
hashAlgDigSz = TPM2_GetHashDigestSize(hashAlg);
/* Setup load command */
XMEMSET(&loadExtIn, 0, sizeof(loadExtIn));
loadExtIn.hierarchy = TPM_RH_NULL;
/* Setup private key */
loadExtIn.inPrivate.sensitiveArea.sensitiveType = TPM_ALG_SYMCIPHER;
if (key->handle.auth.size > 0) {
loadExtIn.inPrivate.sensitiveArea.authValue.size = key->handle.auth.size;
XMEMCPY(loadExtIn.inPrivate.sensitiveArea.authValue.buffer,
key->handle.auth.buffer, key->handle.auth.size);
}
loadExtIn.inPrivate.sensitiveArea.seedValue.size = hashAlgDigSz;
rc = wolfTPM2_GetRandom(dev,
loadExtIn.inPrivate.sensitiveArea.seedValue.buffer,
loadExtIn.inPrivate.sensitiveArea.seedValue.size);
if (rc != 0)
goto exit;
loadExtIn.inPrivate.sensitiveArea.sensitive.sym.size = keySz;
XMEMCPY(loadExtIn.inPrivate.sensitiveArea.sensitive.sym.buffer,
keyBuf, keySz);
/* Setup public key */
rc = wolfTPM2_GetKeyTemplate_Symmetric(&loadExtIn.inPublic.publicArea,
keySz * 8, alg, YES, YES);
if (rc != 0)
goto exit;
loadExtIn.inPublic.publicArea.nameAlg = hashAlg;
loadExtIn.inPublic.publicArea.unique.sym.size = hashAlgDigSz;
rc = wolfTPM2_ComputeSymmetricUnique(dev, hashAlg,
&loadExtIn.inPrivate.sensitiveArea,
&loadExtIn.inPublic.publicArea.unique.sym);
if (rc != 0)
goto exit;
/* Load private key */
rc = TPM2_LoadExternal(&loadExtIn, &loadExtOut);
if (rc == TPM_RC_SUCCESS) {
key->handle.hndl = loadExtOut.objectHandle;
wolfTPM2_CopySymmetric(&key->handle.symmetric,
&loadExtIn.inPublic.publicArea.parameters.asymDetail.symmetric);
wolfTPM2_CopyPub(&key->pub, &loadExtIn.inPublic);
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_LoadSymmetricKey: 0x%x\n",
(word32)loadExtOut.objectHandle);
#endif
return rc;
}
exit:
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_LoadExternal: failed %d: %s\n",
rc, wolfTPM2_GetRCString(rc));
#endif
return rc;
}
return rc;
}
/* EncryptDecrypt */
int wolfTPM2_EncryptDecryptBlock(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
const byte* in, byte* out, word32 inOutSz, byte* iv, word32 ivSz,
int isDecrypt)
{
int rc;
EncryptDecrypt2_In encDecIn;
EncryptDecrypt2_Out encDecOut;
if (dev == NULL || key == NULL || in == NULL || out == NULL ||
inOutSz == 0) {
return BAD_FUNC_ARG;
}
/* set session auth for key */
wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
XMEMSET(&encDecIn, 0, sizeof(encDecIn));
encDecIn.keyHandle = key->handle.hndl;
if (iv == NULL || ivSz == 0) {
encDecIn.ivIn.size = MAX_AES_BLOCK_SIZE_BYTES; /* zeros */
}
else {
encDecIn.ivIn.size = ivSz;
XMEMCPY(encDecIn.ivIn.buffer, iv, ivSz);
}
encDecIn.decrypt = isDecrypt;
/* use symmetric algorithm from key */
encDecIn.mode = key->pub.publicArea.parameters.symDetail.sym.mode.aes;
encDecIn.inData.size = inOutSz;
XMEMCPY(encDecIn.inData.buffer, in, inOutSz);
/* make sure its multiple of block size */
encDecIn.inData.size = (encDecIn.inData.size +
MAX_AES_BLOCK_SIZE_BYTES - 1) & ~(MAX_AES_BLOCK_SIZE_BYTES - 1);
rc = TPM2_EncryptDecrypt2(&encDecIn, &encDecOut);
if (rc == TPM_RC_COMMAND_CODE) { /* some TPM's may not support command */
/* try to enable support */
rc = wolfTPM2_SetCommand(dev, TPM_CC_EncryptDecrypt2, YES);
if (rc == TPM_RC_SUCCESS) {
/* try command again */
rc = TPM2_EncryptDecrypt2(&encDecIn, &encDecOut);
}
}
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_EncryptDecrypt2 failed 0x%x: %s\n", rc,
TPM2_GetRCString(rc));
#endif
return rc;
}
/* update IV */
if (iv) {
if (ivSz < encDecOut.ivOut.size)
ivSz = encDecOut.ivOut.size;
XMEMCPY(iv, encDecOut.ivOut.buffer, ivSz);
}
/* return block */
if (inOutSz > encDecOut.outData.size)
inOutSz = encDecOut.outData.size;
XMEMCPY(out, encDecOut.outData.buffer, inOutSz);
return rc;
}
int wolfTPM2_EncryptDecrypt(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
const byte* in, byte* out, word32 inOutSz,
byte* iv, word32 ivSz, int isDecrypt)
{
int rc = 0;
word32 pos = 0, xfer;
while (pos < inOutSz) {
xfer = inOutSz - pos;
if (xfer > MAX_DIGEST_BUFFER)
xfer = MAX_DIGEST_BUFFER;
rc = wolfTPM2_EncryptDecryptBlock(dev, key, &in[pos], &out[pos],
xfer, iv, ivSz, isDecrypt);
if (rc != TPM_RC_SUCCESS)
break;
pos += xfer;
}
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_EncryptDecrypt: 0x%x: %s, %d bytes\n",
rc, TPM2_GetRCString(rc), inOutSz);
#endif
return rc;
}
int wolfTPM2_SetCommand(WOLFTPM2_DEV* dev, TPM_CC commandCode, int enableFlag)
{
int rc = TPM_RC_COMMAND_CODE; /* not supported */
#if defined(WOLFTPM_ST33) || defined(WOLFTPM_AUTODETECT)
if (TPM2_GetVendorID() == TPM_VENDOR_STM) {
SetCommandSet_In in;
/* Enable commands (like TPM2_EncryptDecrypt2) */
XMEMSET(&in, 0, sizeof(in));
in.authHandle = TPM_RH_PLATFORM;
in.commandCode = commandCode;
in.enableFlag = enableFlag;
rc = TPM2_SetCommandSet(&in);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_SetCommandSet failed 0x%x: %s\n", rc,
TPM2_GetRCString(rc));
#endif
}
}
#else
(void)commandCode;
(void)enableFlag;
#endif
(void)dev;
return rc;
}
/* HMAC */
int wolfTPM2_LoadKeyedHashKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
WOLFTPM2_HANDLE* parent, int hashAlg, const byte* keyBuf, word32 keySz,
const byte* usageAuth, word32 usageAuthSz)
{
int rc;
Create_In createIn;
Create_Out createOut;
Load_In loadIn;
Load_Out loadOut;
int hashAlgDigSz;
if (dev == NULL || key == NULL || parent == NULL || keyBuf == NULL) {
return BAD_FUNC_ARG;
}
if (keySz == 0 || keySz > MAX_SYM_DATA) {
return BUFFER_E;
}
hashAlgDigSz = TPM2_GetHashDigestSize(hashAlg);
if (hashAlgDigSz <= 0) {
return BAD_FUNC_ARG;
}
/* clear output key buffer */
XMEMSET(key, 0, sizeof(WOLFTPM2_KEY));
/* set session auth for parent key */
wolfTPM2_SetAuthHandle(dev, 0, parent);
XMEMSET(&createIn, 0, sizeof(createIn));
createIn.parentHandle = parent->hndl;
if (usageAuth) {
createIn.inSensitive.sensitive.userAuth.size = usageAuthSz;
XMEMCPY(createIn.inSensitive.sensitive.userAuth.buffer, usageAuth,
createIn.inSensitive.sensitive.userAuth.size);
}
createIn.inSensitive.sensitive.data.size = keySz;
XMEMCPY(createIn.inSensitive.sensitive.data.buffer, keyBuf, keySz);
rc = wolfTPM2_GetKeyTemplate_KeyedHash(&createIn.inPublic.publicArea,
hashAlg, YES, NO);
if (rc != 0) {
return rc;
}
rc = TPM2_Create(&createIn, &createOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_Create key failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
#endif
return rc;
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_Create key: pub %d, priv %d\n", createOut.outPublic.size,
createOut.outPrivate.size);
TPM2_PrintPublicArea(&createOut.outPublic);
#endif
wolfTPM2_CopySymmetric(&key->handle.symmetric,
&createOut.outPublic.publicArea.parameters.asymDetail.symmetric);
wolfTPM2_CopyPub(&key->pub, &createOut.outPublic);
/* Load new key */
XMEMSET(&loadIn, 0, sizeof(loadIn));
loadIn.parentHandle = parent->hndl;
wolfTPM2_CopyPriv(&loadIn.inPrivate, &createOut.outPrivate);
wolfTPM2_CopyPub(&loadIn.inPublic, &key->pub);
rc = TPM2_Load(&loadIn, &loadOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_Load key failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
#endif
return rc;
}
key->handle.hndl = loadOut.objectHandle;
wolfTPM2_CopyAuth(&key->handle.auth, &createIn.inSensitive.sensitive.userAuth);
wolfTPM2_CopyName(&key->handle.name, &loadOut.name);
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_LoadKeyedHashKey Key Handle 0x%x\n",
(word32)key->handle.hndl);
#endif
return rc;
}
int wolfTPM2_HmacStart(WOLFTPM2_DEV* dev, WOLFTPM2_HMAC* hmac,
WOLFTPM2_HANDLE* parent, TPMI_ALG_HASH hashAlg, const byte* keyBuf,
word32 keySz, const byte* usageAuth, word32 usageAuthSz)
{
int rc;
HMAC_Start_In in;
HMAC_Start_Out out;
if (dev == NULL || hmac == NULL || hashAlg == TPM_ALG_NULL) {
return BAD_FUNC_ARG;
}
/* Capture usage auth */
if (usageAuthSz > sizeof(hmac->hash.handle.auth.buffer))
usageAuthSz = sizeof(hmac->hash.handle.auth.buffer);
hmac->hash.handle.auth.size = usageAuthSz;
XMEMCPY(hmac->hash.handle.auth.buffer, usageAuth, usageAuthSz);
if (!hmac->hmacKeyLoaded || hmac->key.handle.hndl == TPM_RH_NULL) {
/* Load Keyed Hash Key */
rc = wolfTPM2_LoadKeyedHashKey(dev, &hmac->key, parent, hashAlg, keyBuf,
keySz, usageAuth, usageAuthSz);
if (rc != 0) {
return rc;
}
hmac->hmacKeyLoaded = 1;
}
/* set session auth for hmac key */
wolfTPM2_SetAuthHandle(dev, 0, &hmac->hash.handle);
/* Setup HMAC start command */
XMEMSET(&in, 0, sizeof(in));
in.handle = hmac->key.handle.hndl;
wolfTPM2_CopyAuth(&in.auth, &hmac->hash.handle.auth);
in.hashAlg = hashAlg;
rc = TPM2_HMAC_Start(&in, &out);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_HMAC_Start failed 0x%x: %s\n", rc,
TPM2_GetRCString(rc));
#endif
return rc;
}
/* Capture hash sequence handle */
hmac->hash.handle.hndl = out.sequenceHandle;
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_HmacStart: Handle 0x%x\n",
(word32)out.sequenceHandle);
#endif
return rc;
}
int wolfTPM2_HmacUpdate(WOLFTPM2_DEV* dev, WOLFTPM2_HMAC* hmac,
const byte* data, word32 dataSz)
{
if (dev == NULL || hmac == NULL) {
return BAD_FUNC_ARG;
}
return wolfTPM2_HashUpdate(dev, &hmac->hash, data, dataSz);
}
int wolfTPM2_HmacFinish(WOLFTPM2_DEV* dev, WOLFTPM2_HMAC* hmac,
byte* digest, word32* digestSz)
{
int rc;
if (dev == NULL || hmac == NULL) {
return BAD_FUNC_ARG;
}
rc = wolfTPM2_HashFinish(dev, &hmac->hash, digest, digestSz);
if (!hmac->hmacKeyKeep) {
/* unload HMAC key */
wolfTPM2_UnloadHandle(dev, &hmac->key.handle);
hmac->hmacKeyLoaded = 0;
}
return rc;
}
/* performs a reset sequence */
int wolfTPM2_Shutdown(WOLFTPM2_DEV* dev, int doStartup)
{
int rc;
Shutdown_In shutdownIn;
Startup_In startupIn;
if (dev == NULL) {
return BAD_FUNC_ARG;
}
/* shutdown */
XMEMSET(&shutdownIn, 0, sizeof(shutdownIn));
shutdownIn.shutdownType = TPM_SU_CLEAR;
rc = TPM2_Shutdown(&shutdownIn);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_Shutdown failed 0x%x: %s\n", rc, TPM2_GetRCString(rc));
#endif
}
/* startup */
if (doStartup) {
XMEMSET(&startupIn, 0, sizeof(startupIn));
startupIn.startupType = TPM_SU_CLEAR;
rc = TPM2_Startup(&startupIn);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_Startup failed %d: %s\n",
rc, wolfTPM2_GetRCString(rc));
#endif
return rc;
}
}
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_Shutdown complete\n");
#endif
return rc;
}
int wolfTPM2_UnloadHandles(WOLFTPM2_DEV* dev, word32 handleStart,
word32 handleCount)
{
int rc = TPM_RC_SUCCESS;
word32 hndl;
WOLFTPM2_HANDLE handle;
if (dev == NULL) {
return BAD_FUNC_ARG;
}
XMEMSET(&handle, 0, sizeof(handle));
wolfTPM2_CopyAuth(&handle.auth, &dev->session[0].auth);
for (hndl=handleStart; hndl < handleStart+handleCount; hndl++) {
handle.hndl = hndl;
/* ignore return code failures */
(void)wolfTPM2_UnloadHandle(dev, &handle);
}
return rc;
}
int wolfTPM2_UnloadHandles_AllTransient(WOLFTPM2_DEV* dev)
{
return wolfTPM2_UnloadHandles(dev, TRANSIENT_FIRST, MAX_HANDLE_NUM);
}
int wolfTPM2_ChangePlatformAuth(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* session)
{
int rc = 0;
HierarchyChangeAuth_In in;
if (dev == NULL) {
return BAD_FUNC_ARG;
}
XMEMSET(&in, 0, sizeof(in));
in.authHandle = TPM_RH_PLATFORM;
/* use parameter encryption if session supplied */
if (session != NULL) {
rc = wolfTPM2_SetAuthSession(dev, 1, session, (TPMA_SESSION_decrypt |
TPMA_SESSION_encrypt | TPMA_SESSION_continueSession));
}
if (rc == 0) {
/* TPM 2.0 PCR's are typically SHA-1 and SHA2-256 */
in.newAuth.size = TPM2_GetHashDigestSize(WOLFTPM2_WRAP_DIGEST);
if (in.newAuth.size <= 0) {
rc = BAD_FUNC_ARG;
}
}
if (rc == 0) {
rc = TPM2_GetNonce(in.newAuth.buffer, in.newAuth.size);
}
if (rc == 0) {
rc = TPM2_HierarchyChangeAuth(&in);
}
#ifdef DEBUG_WOLFTPM
if (rc == 0) {
printf("Platform auth set to %d bytes of random\n", in.newAuth.size);
#ifdef WOLFTPM_DEBUG_VERBOSE
printf("\tAuth Sz %d\n", in.newAuth.size);
TPM2_PrintBin(in.newAuth.buffer, in.newAuth.size);
#endif
}
else {
printf("Error %d setting platform auth! %s\n",
rc, wolfTPM2_GetRCString(rc));
}
#endif
/* ensure the random secret is not left in stack */
TPM2_ForceZero(in.newAuth.buffer, in.newAuth.size);
return rc;
}
/******************************************************************************/
/* --- END Wrapper Device Functions-- */
/******************************************************************************/
/******************************************************************************/
/* --- BEGIN Utility Functions -- */
/******************************************************************************/
int GetKeyTemplateRSA(TPMT_PUBLIC* publicTemplate,
TPM_ALG_ID nameAlg, TPMA_OBJECT objectAttributes, int keyBits, long exponent,
TPM_ALG_ID sigScheme, TPM_ALG_ID sigHash)
{
if (publicTemplate == NULL)
return BAD_FUNC_ARG;
XMEMSET(publicTemplate, 0, sizeof(TPMT_PUBLIC));
publicTemplate->type = TPM_ALG_RSA;
publicTemplate->unique.rsa.size = keyBits / 8;
publicTemplate->nameAlg = nameAlg;
publicTemplate->objectAttributes = objectAttributes;
publicTemplate->parameters.rsaDetail.keyBits = keyBits;
publicTemplate->parameters.rsaDetail.exponent = (UINT32)exponent;
publicTemplate->parameters.rsaDetail.scheme.scheme = sigScheme;
publicTemplate->parameters.rsaDetail.scheme.details.anySig.hashAlg = sigHash;
/* For fixedParent or (decrypt and restricted) enable symmetric */
if ((objectAttributes & TPMA_OBJECT_fixedParent) ||
((objectAttributes & TPMA_OBJECT_decrypt) &&
(objectAttributes & TPMA_OBJECT_restricted))) {
publicTemplate->parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES;
publicTemplate->parameters.rsaDetail.symmetric.keyBits.aes = 128;
publicTemplate->parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_CFB;
}
else {
publicTemplate->parameters.rsaDetail.symmetric.algorithm = TPM_ALG_NULL;
}
return TPM_RC_SUCCESS;
}
int GetKeyTemplateECC(TPMT_PUBLIC* publicTemplate,
TPM_ALG_ID nameAlg, TPMA_OBJECT objectAttributes, TPM_ECC_CURVE curve,
TPM_ALG_ID sigScheme, TPM_ALG_ID sigHash)
{
int curveSz = TPM2_GetCurveSize(curve);
if (publicTemplate == NULL || curveSz == 0)
return BAD_FUNC_ARG;
#if defined(NO_ECC256) && defined(HAVE_ECC384) && ECC_MIN_KEY_SZ <= 384
/* make sure we use a curve that is enabled */
if (curve == TPM_ECC_NIST_P256) {
curve = TPM_ECC_NIST_P384;
nameAlg = TPM_ALG_SHA384;
sigHash = TPM_ALG_SHA384;
}
#endif
XMEMSET(publicTemplate, 0, sizeof(TPMT_PUBLIC));
publicTemplate->type = TPM_ALG_ECC;
publicTemplate->nameAlg = nameAlg;
publicTemplate->unique.ecc.x.size = curveSz;
publicTemplate->unique.ecc.y.size = curveSz;
publicTemplate->objectAttributes = objectAttributes;
/* For fixedParent or (decrypt and restricted) enable symmetric */
if ((objectAttributes & TPMA_OBJECT_fixedParent) ||
((objectAttributes & TPMA_OBJECT_decrypt) &&
(objectAttributes & TPMA_OBJECT_restricted))) {
publicTemplate->parameters.eccDetail.symmetric.algorithm = TPM_ALG_AES;
publicTemplate->parameters.eccDetail.symmetric.keyBits.aes = 128;
publicTemplate->parameters.eccDetail.symmetric.mode.aes = TPM_ALG_CFB;
}
else {
publicTemplate->parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL;
}
/* TPM_ALG_ECDSA or TPM_ALG_ECDH */
publicTemplate->parameters.eccDetail.scheme.scheme = sigScheme;
publicTemplate->parameters.eccDetail.scheme.details.ecdsa.hashAlg = sigHash;
publicTemplate->parameters.eccDetail.curveID = curve;
publicTemplate->parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
return TPM_RC_SUCCESS;
}
int wolfTPM2_GetKeyTemplate_RSA_ex(TPMT_PUBLIC* publicTemplate,
TPM_ALG_ID nameAlg, TPMA_OBJECT objectAttributes, int keyBits, long exponent,
TPM_ALG_ID sigScheme, TPM_ALG_ID sigHash)
{
return GetKeyTemplateRSA(publicTemplate, nameAlg,
objectAttributes, keyBits, exponent, sigScheme, sigHash);
}
int wolfTPM2_GetKeyTemplate_RSA(TPMT_PUBLIC* publicTemplate,
TPMA_OBJECT objectAttributes)
{
return GetKeyTemplateRSA(publicTemplate, WOLFTPM2_WRAP_DIGEST,
objectAttributes, WOLFTPM2_WRAP_RSA_KEY_BITS, WOLFTPM2_WRAP_RSA_EXPONENT,
TPM_ALG_NULL, WOLFTPM2_WRAP_DIGEST);
}
int wolfTPM2_GetKeyTemplate_ECC_ex(TPMT_PUBLIC* publicTemplate,
TPM_ALG_ID nameAlg, TPMA_OBJECT objectAttributes, TPM_ECC_CURVE curve,
TPM_ALG_ID sigScheme, TPM_ALG_ID sigHash)
{
return GetKeyTemplateECC(publicTemplate, nameAlg,
objectAttributes, curve, sigScheme, sigHash);
}
int wolfTPM2_GetKeyTemplate_ECC(TPMT_PUBLIC* publicTemplate,
TPMA_OBJECT objectAttributes, TPM_ECC_CURVE curve, TPM_ALG_ID sigScheme)
{
return GetKeyTemplateECC(publicTemplate, WOLFTPM2_WRAP_DIGEST,
objectAttributes, curve, sigScheme, WOLFTPM2_WRAP_DIGEST);
}
int wolfTPM2_GetKeyTemplate_Symmetric(TPMT_PUBLIC* publicTemplate, int keyBits,
TPM_ALG_ID algMode, int isSign, int isDecrypt)
{
if (publicTemplate == NULL)
return BAD_FUNC_ARG;
#ifdef WOLFTPM_MICROCHIP
isSign = 0; /* Microchip TPM does not like "sign" set for symmetric keys */
#endif
XMEMSET(publicTemplate, 0, sizeof(TPMT_PUBLIC));
publicTemplate->type = TPM_ALG_SYMCIPHER;
publicTemplate->nameAlg = WOLFTPM2_WRAP_DIGEST;
publicTemplate->unique.sym.size = keyBits / 8;
publicTemplate->objectAttributes = (
TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
TPMA_OBJECT_noDA | (isSign ? TPMA_OBJECT_sign : 0) |
(isDecrypt ? TPMA_OBJECT_decrypt : 0));
publicTemplate->parameters.symDetail.sym.algorithm = TPM_ALG_AES;
publicTemplate->parameters.symDetail.sym.keyBits.sym = keyBits;
publicTemplate->parameters.symDetail.sym.mode.sym = algMode;
return TPM_RC_SUCCESS;
}
int wolfTPM2_GetKeyTemplate_KeyedHash(TPMT_PUBLIC* publicTemplate,
TPM_ALG_ID hashAlg, int isSign, int isDecrypt)
{
if (publicTemplate == NULL)
return BAD_FUNC_ARG;
XMEMSET(publicTemplate, 0, sizeof(TPMT_PUBLIC));
publicTemplate->type = TPM_ALG_KEYEDHASH;
publicTemplate->nameAlg = WOLFTPM2_WRAP_DIGEST;
publicTemplate->objectAttributes = (
TPMA_OBJECT_userWithAuth |
TPMA_OBJECT_noDA |
(isSign ? TPMA_OBJECT_sign : 0) |
(isDecrypt ? TPMA_OBJECT_decrypt : 0));
publicTemplate->parameters.keyedHashDetail.scheme.scheme = TPM_ALG_HMAC;
publicTemplate->parameters.keyedHashDetail.scheme.details.hmac.hashAlg = hashAlg;
return TPM_RC_SUCCESS;
}
int wolfTPM2_GetKeyTemplate_KeySeal(TPMT_PUBLIC* publicTemplate, TPM_ALG_ID nameAlg)
{
if (publicTemplate == NULL)
return BAD_FUNC_ARG;
/* Seal Object can be only of type KEYEDHASH and can not be used for
* signing or encryption. Hash algorithm can be chosen by the developer.
*/
XMEMSET(publicTemplate, 0, sizeof(TPMT_PUBLIC));
publicTemplate->type = TPM_ALG_KEYEDHASH;
publicTemplate->nameAlg = nameAlg;
publicTemplate->objectAttributes = (
TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent |
TPMA_OBJECT_noDA);
publicTemplate->parameters.keyedHashDetail.scheme.scheme = TPM_ALG_NULL;
return TPM_RC_SUCCESS;
}
int wolfTPM2_GetKeyTemplate_RSA_EK(TPMT_PUBLIC* publicTemplate)
{
int ret;
TPMA_OBJECT objectAttributes = (
TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent |
TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_adminWithPolicy |
TPMA_OBJECT_restricted | TPMA_OBJECT_decrypt);
ret = GetKeyTemplateRSA(publicTemplate, TPM_ALG_SHA256,
objectAttributes, 2048, 0, TPM_ALG_NULL, TPM_ALG_NULL);
if (ret == 0) {
publicTemplate->authPolicy.size = sizeof(TPM_20_EK_AUTH_POLICY);
XMEMCPY(publicTemplate->authPolicy.buffer,
TPM_20_EK_AUTH_POLICY, publicTemplate->authPolicy.size);
}
return ret;
}
int wolfTPM2_GetKeyTemplate_ECC_EK(TPMT_PUBLIC* publicTemplate)
{
int ret;
TPMA_OBJECT objectAttributes = (
TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent |
TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_adminWithPolicy |
TPMA_OBJECT_restricted | TPMA_OBJECT_decrypt);
ret = GetKeyTemplateECC(publicTemplate, TPM_ALG_SHA256,
objectAttributes, TPM_ECC_NIST_P256, TPM_ALG_NULL, TPM_ALG_NULL);
if (ret == 0) {
publicTemplate->authPolicy.size = sizeof(TPM_20_EK_AUTH_POLICY);
XMEMCPY(publicTemplate->authPolicy.buffer,
TPM_20_EK_AUTH_POLICY, publicTemplate->authPolicy.size);
}
return ret;
}
int wolfTPM2_GetKeyTemplate_RSA_SRK(TPMT_PUBLIC* publicTemplate)
{
TPMA_OBJECT objectAttributes = (
TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent |
TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
TPMA_OBJECT_restricted | TPMA_OBJECT_decrypt | TPMA_OBJECT_noDA);
return GetKeyTemplateRSA(publicTemplate, TPM_ALG_SHA256,
objectAttributes, 2048, 0, TPM_ALG_NULL, TPM_ALG_NULL);
}
int wolfTPM2_GetKeyTemplate_ECC_SRK(TPMT_PUBLIC* publicTemplate)
{
TPMA_OBJECT objectAttributes = (
TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent |
TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
TPMA_OBJECT_restricted | TPMA_OBJECT_decrypt | TPMA_OBJECT_noDA);
return GetKeyTemplateECC(publicTemplate, TPM_ALG_SHA256,
objectAttributes, TPM_ECC_NIST_P256, TPM_ALG_NULL, TPM_ALG_NULL);
}
int wolfTPM2_GetKeyTemplate_RSA_AIK(TPMT_PUBLIC* publicTemplate)
{
int ret;
TPMA_OBJECT objectAttributes = (
TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent |
TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
TPMA_OBJECT_restricted | TPMA_OBJECT_sign | TPMA_OBJECT_noDA);
ret = GetKeyTemplateRSA(publicTemplate, TPM_ALG_SHA256,
objectAttributes, 2048, 0, TPM_ALG_RSASSA, TPM_ALG_SHA256);
if (ret == 0) {
publicTemplate->parameters.rsaDetail.symmetric.algorithm = TPM_ALG_NULL;
}
return ret;
}
int wolfTPM2_GetKeyTemplate_ECC_AIK(TPMT_PUBLIC* publicTemplate)
{
int ret;
TPMA_OBJECT objectAttributes = (
TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent |
TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
TPMA_OBJECT_restricted | TPMA_OBJECT_sign | TPMA_OBJECT_noDA);
ret = GetKeyTemplateECC(publicTemplate, TPM_ALG_SHA256,
objectAttributes, TPM_ECC_NIST_P256, TPM_ALG_ECDSA, TPM_ALG_SHA256);
if (ret == 0) {
publicTemplate->parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL;
}
return ret;
}
/* Returns key size (in bytes) for the public template */
static int GetKeyTemplateSize(TPMT_PUBLIC* publicTemplate)
{
int ret;
if (publicTemplate == NULL) {
return BAD_FUNC_ARG;
}
switch (publicTemplate->type) {
case TPM_ALG_RSA:
ret = publicTemplate->parameters.rsaDetail.keyBits / 8;
break;
case TPM_ALG_ECC:
ret = TPM2_GetCurveSize(
publicTemplate->parameters.eccDetail.curveID);
break;
case TPM_ALG_SYMCIPHER:
ret = publicTemplate->parameters.symDetail.sym.keyBits.sym / 8;
break;
case TPM_ALG_KEYEDHASH:
default:
ret = BAD_FUNC_ARG;
}
return ret;
}
int wolfTPM2_SetKeyTemplate_Unique(TPMT_PUBLIC* publicTemplate,
const byte* unique, int uniqueSz)
{
int ret = 0;
int keySz;
if (publicTemplate == NULL || (unique != NULL && uniqueSz <= 0)) {
return BAD_FUNC_ARG;
}
keySz = GetKeyTemplateSize(publicTemplate);
if (keySz <= 0) {
return BAD_FUNC_ARG;
}
switch (publicTemplate->type) {
case TPM_ALG_RSA:
if (uniqueSz == 0) {
uniqueSz = keySz;
}
else if (uniqueSz > keySz) {
uniqueSz = keySz;
}
if (uniqueSz > (int)sizeof(publicTemplate->unique.rsa.buffer)) {
uniqueSz = (int)sizeof(publicTemplate->unique.rsa.buffer);
}
if (unique == NULL) {
XMEMSET(publicTemplate->unique.rsa.buffer, 0, uniqueSz);
}
else {
XMEMCPY(publicTemplate->unique.rsa.buffer, unique, uniqueSz);
}
publicTemplate->unique.rsa.size = uniqueSz;
break;
case TPM_ALG_ECC:
/* ECC uses X and Y */
if (uniqueSz == 0) {
uniqueSz = keySz * 2;
}
else if (uniqueSz > keySz * 2) {
uniqueSz = keySz * 2;
}
uniqueSz /= 2;
if (uniqueSz > (int)sizeof(publicTemplate->unique.ecc.x.buffer)) {
uniqueSz = (int)sizeof(publicTemplate->unique.ecc.x.buffer);
}
if (unique == NULL) {
XMEMSET(publicTemplate->unique.ecc.x.buffer, 0, uniqueSz);
XMEMSET(publicTemplate->unique.ecc.y.buffer, 0, uniqueSz);
}
else {
XMEMCPY(publicTemplate->unique.ecc.x.buffer, unique, uniqueSz);
XMEMCPY(publicTemplate->unique.ecc.y.buffer, unique + uniqueSz, uniqueSz);
}
publicTemplate->unique.ecc.x.size = uniqueSz;
publicTemplate->unique.ecc.y.size = uniqueSz;
break;
case TPM_ALG_SYMCIPHER:
if (uniqueSz == 0) {
uniqueSz = keySz;
}
else if (uniqueSz > keySz) {
uniqueSz = keySz;
}
if (uniqueSz > (int)sizeof(publicTemplate->unique.sym.buffer)) {
uniqueSz = (int)sizeof(publicTemplate->unique.sym.buffer);
}
if (unique == NULL) {
XMEMSET(publicTemplate->unique.sym.buffer, 0, uniqueSz);
}
else {
XMEMCPY(publicTemplate->unique.sym.buffer, unique, uniqueSz);
}
publicTemplate->unique.sym.size = uniqueSz;
break;
case TPM_ALG_KEYEDHASH:
/* not supported */
ret = BAD_FUNC_ARG;
break;
default:
ret = BAD_FUNC_ARG;
break;
}
return ret;
}
int wolfTPM2_GetNvAttributesTemplate(TPM_HANDLE auth, word32* nvAttributes)
{
if (nvAttributes == NULL)
return BAD_FUNC_ARG;
*nvAttributes = (
TPMA_NV_AUTHWRITE | /* password or HMAC can authorize writing */
TPMA_NV_AUTHREAD | /* password or HMAC can authorize reading */
TPMA_NV_OWNERREAD | /* Allow owner to read */
TPMA_NV_NO_DA /* Don't increment dictionary attack counter */
);
if (auth == TPM_RH_PLATFORM) {
*nvAttributes |= (
TPMA_NV_PLATFORMCREATE | /* Platform created NV */
TPMA_NV_PPWRITE | /* Write may be authorized by platform */
TPMA_NV_PPREAD /* Read may be authorized by platform */
);
}
else if (auth == TPM_RH_OWNER) {
*nvAttributes |= (
TPMA_NV_OWNERWRITE /* Owner Hierarchy auth can be used to write */
);
}
return 0;
}
int wolfTPM2_CreateEK(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* ekKey, TPM_ALG_ID alg)
{
int rc;
TPMT_PUBLIC publicTemplate;
if (alg == TPM_ALG_RSA) {
rc = wolfTPM2_GetKeyTemplate_RSA_EK(&publicTemplate);
}
else if (alg == TPM_ALG_ECC) {
rc = wolfTPM2_GetKeyTemplate_ECC_EK(&publicTemplate);
}
else {
/* Supported algorithms for EK are only RSA 2048-bit & ECC P256 */
return BAD_FUNC_ARG;
}
/* GetKeyTemplate check */
if (rc != 0)
return rc;
rc = wolfTPM2_CreatePrimaryKey(dev, ekKey, TPM_RH_ENDORSEMENT,
&publicTemplate, NULL, 0);
return rc;
}
int wolfTPM2_CreateSRK(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* srkKey, TPM_ALG_ID alg,
const byte* auth, int authSz)
{
int rc;
TPMT_PUBLIC publicTemplate;
/* Supported algorithms for SRK are only 2048bit RSA & ECC */
if (alg == TPM_ALG_RSA) {
rc = wolfTPM2_GetKeyTemplate_RSA_SRK(&publicTemplate);
}
else if (alg == TPM_ALG_ECC) {
rc = wolfTPM2_GetKeyTemplate_ECC_SRK(&publicTemplate);
}
else {
/* Supported algorithms for SRK are only RSA 2048-bit & ECC P256 */
return BAD_FUNC_ARG;
}
/* GetKeyTemplate check */
if (rc != 0)
return rc;
rc = wolfTPM2_CreatePrimaryKey(dev, srkKey, TPM_RH_OWNER,
&publicTemplate, auth, authSz);
return rc;
}
int wolfTPM2_CreateAndLoadAIK(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* aikKey,
TPM_ALG_ID alg, WOLFTPM2_KEY* srkKey, const byte* auth, int authSz)
{
int rc;
TPMT_PUBLIC publicTemplate;
if (alg == TPM_ALG_RSA) {
rc = wolfTPM2_GetKeyTemplate_RSA_AIK(&publicTemplate);
}
else if (alg == TPM_ALG_ECC) {
rc = wolfTPM2_GetKeyTemplate_ECC_AIK(&publicTemplate);
}
else {
return BAD_FUNC_ARG;
}
/* GetKeyTemplate check */
if (rc != 0)
return rc;
rc = wolfTPM2_CreateAndLoadKey(dev, aikKey, &srkKey->handle,
&publicTemplate, auth, authSz);
return rc;
}
int wolfTPM2_CreateKeySeal(WOLFTPM2_DEV* dev, WOLFTPM2_KEYBLOB* keyBlob,
WOLFTPM2_HANDLE* parent, TPMT_PUBLIC* publicTemplate,
const byte* auth, int authSz, const byte* sealData, int sealSize)
{
return wolfTPM2_CreateKeySeal_ex(dev, keyBlob, parent, publicTemplate, auth,
authSz, TPM_ALG_NULL, NULL, 0, sealData, sealSize);
}
int wolfTPM2_CreateKeySeal_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEYBLOB* keyBlob,
WOLFTPM2_HANDLE* parent, TPMT_PUBLIC* publicTemplate,
const byte* auth, int authSz, TPM_ALG_ID pcrAlg, byte* pcrArray,
word32 pcrArraySz, const byte* sealData, int sealSize)
{
int rc;
Create_In createIn;
Create_Out createOut;
if (dev == NULL || keyBlob == NULL || parent == NULL || publicTemplate == NULL)
return BAD_FUNC_ARG;
/* Seal size is limited to TCG defined MAX_SYM_DATA, which is 128 bytes */
if (sealSize < 0 || sealSize > MAX_SYM_DATA) {
#ifdef DEBUG_WOLFTPM
printf("Seal size %d should not be larger than %d bytes\n",
sealSize, MAX_SYM_DATA);
#endif
return BAD_FUNC_ARG;
}
/* clear output key buffer */
XMEMSET(keyBlob, 0, sizeof(WOLFTPM2_KEYBLOB));
XMEMSET(&createOut, 0, sizeof(createOut)); /* make sure pub struct is zero init */
/* set session auth for parent key */
wolfTPM2_SetAuthHandle(dev, 0, parent);
XMEMSET(&createIn, 0, sizeof(createIn));
createIn.parentHandle = parent->hndl;
if (auth) {
createIn.inSensitive.sensitive.userAuth.size = authSz;
XMEMCPY(createIn.inSensitive.sensitive.userAuth.buffer, auth,
createIn.inSensitive.sensitive.userAuth.size);
}
wolfTPM2_CopyPubT(&createIn.inPublic.publicArea, publicTemplate);
/* Seal user (arbitrary) data in the newly generated TPM key */
createIn.inSensitive.sensitive.data.size = sealSize;
XMEMCPY(createIn.inSensitive.sensitive.data.buffer, sealData,
createIn.inSensitive.sensitive.data.size);
/* set the pcr selection if passed in */
if (pcrArray != NULL) {
TPM2_SetupPCRSelArray(&createIn.creationPCR, pcrAlg, pcrArray,
pcrArraySz);
}
rc = TPM2_Create(&createIn, &createOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_CreateKeySeal failed %d: %s\n",
rc, wolfTPM2_GetRCString(rc));
#endif
return rc;
}
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_CreateKeySeal generated key with: pub %d, priv %d\n",
createOut.outPublic.size, createOut.outPrivate.size);
TPM2_PrintPublicArea(&createOut.outPublic);
#endif
wolfTPM2_CopyAuth(&keyBlob->handle.auth, &createIn.inSensitive.sensitive.userAuth);
wolfTPM2_CopySymmetric(&keyBlob->handle.symmetric,
&createOut.outPublic.publicArea.parameters.asymDetail.symmetric);
wolfTPM2_CopyPub(&keyBlob->pub, &createOut.outPublic);
wolfTPM2_CopyPriv(&keyBlob->priv, &createOut.outPrivate);
return rc;
}
int wolfTPM2_GetTime(WOLFTPM2_KEY* aikKey, GetTime_Out* getTimeOut)
{
int rc;
GetTime_In getTimeCmd;
if (getTimeOut == NULL)
return BAD_FUNC_ARG;
/* GetTime */
XMEMSET(&getTimeCmd, 0, sizeof(getTimeCmd));
XMEMSET(getTimeOut, 0, sizeof(*getTimeOut));
getTimeCmd.privacyAdminHandle = TPM_RH_ENDORSEMENT;
if (aikKey != NULL) {
TPMT_ASYM_SCHEME* scheme =
&aikKey->pub.publicArea.parameters.asymDetail.scheme;
getTimeCmd.signHandle = aikKey->handle.hndl;
getTimeCmd.inScheme.scheme = scheme->scheme;
getTimeCmd.inScheme.details.any.hashAlg = scheme->details.anySig.hashAlg;
}
else {
getTimeCmd.signHandle = TPM_RH_NULL;
}
getTimeCmd.qualifyingData.size = 0; /* optional */
rc = TPM2_GetTime(&getTimeCmd, getTimeOut);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("TPM2_GetTime failed 0x%x: %s\n", rc, wolfTPM2_GetRCString(rc));
#endif
}
return rc;
}
static void wolfTPM2_CopySymmetric(TPMT_SYM_DEF* out, const TPMT_SYM_DEF* in)
{
if (out == NULL || in == NULL)
return;
out->algorithm = in->algorithm;
switch (out->algorithm) {
case TPM_ALG_XOR:
out->keyBits.xorr = in->keyBits.xorr;
break;
case TPM_ALG_AES:
out->keyBits.aes = in->keyBits.aes;
out->mode.aes = in->mode.aes;
break;
case TPM_ALG_NULL:
break;
default:
out->keyBits.sym = in->keyBits.sym;
out->mode.sym = in->mode.sym;
break;
}
}
static void wolfTPM2_CopyName(TPM2B_NAME* out, const TPM2B_NAME* in)
{
if (out != NULL && in != NULL) {
out->size = in->size;
if (out->size > (UINT16)sizeof(out->name))
out->size = (UINT16)sizeof(out->name);
XMEMCPY(out->name, in->name, out->size);
}
}
static void wolfTPM2_CopyAuth(TPM2B_AUTH* out, const TPM2B_AUTH* in)
{
if (out != NULL && in != NULL) {
out->size = in->size;
if (out->size > (UINT16)sizeof(out->buffer))
out->size = (UINT16)sizeof(out->buffer);
XMEMCPY(out->buffer, in->buffer, out->size);
}
}
static void wolfTPM2_CopyPubT(TPMT_PUBLIC* out, const TPMT_PUBLIC* in)
{
if (out == NULL || in == NULL)
return;
out->type = in->type;
out->nameAlg = in->nameAlg;
out->objectAttributes = in->objectAttributes;
out->authPolicy.size = in->authPolicy.size;
if (out->authPolicy.size > 0) {
if (out->authPolicy.size >
(UINT16)sizeof(out->authPolicy.buffer))
out->authPolicy.size =
(UINT16)sizeof(out->authPolicy.buffer);
XMEMCPY(out->authPolicy.buffer,
in->authPolicy.buffer,
out->authPolicy.size);
}
switch (out->type) {
case TPM_ALG_KEYEDHASH:
out->parameters.keyedHashDetail.scheme =
in->parameters.keyedHashDetail.scheme;
out->unique.keyedHash.size =
in->unique.keyedHash.size;
if (out->unique.keyedHash.size >
(UINT16)sizeof(out->unique.keyedHash.buffer)) {
out->unique.keyedHash.size =
(UINT16)sizeof(out->unique.keyedHash.buffer);
}
XMEMCPY(out->unique.keyedHash.buffer,
in->unique.keyedHash.buffer,
out->unique.keyedHash.size);
break;
case TPM_ALG_SYMCIPHER:
out->parameters.symDetail.sym.algorithm =
in->parameters.symDetail.sym.algorithm;
out->parameters.symDetail.sym.keyBits.sym =
in->parameters.symDetail.sym.keyBits.sym;
out->parameters.symDetail.sym.mode.sym =
in->parameters.symDetail.sym.mode.sym;
out->unique.sym.size =
in->unique.sym.size;
if (out->unique.sym.size >
(UINT16)sizeof(out->unique.sym.buffer)) {
out->unique.sym.size =
(UINT16)sizeof(out->unique.sym.buffer);
}
XMEMCPY(out->unique.sym.buffer,
in->unique.sym.buffer,
out->unique.sym.size);
break;
case TPM_ALG_RSA:
wolfTPM2_CopySymmetric(&out->parameters.rsaDetail.symmetric,
&in->parameters.rsaDetail.symmetric);
out->parameters.rsaDetail.scheme.scheme =
in->parameters.rsaDetail.scheme.scheme;
if (out->parameters.rsaDetail.scheme.scheme != TPM_ALG_NULL)
out->parameters.rsaDetail.scheme.details.anySig.hashAlg =
in->parameters.rsaDetail.scheme.details.anySig.hashAlg;
out->parameters.rsaDetail.keyBits =
in->parameters.rsaDetail.keyBits;
out->parameters.rsaDetail.exponent =
in->parameters.rsaDetail.exponent;
out->unique.rsa.size =
in->unique.rsa.size;
if (out->unique.rsa.size >
(UINT16)sizeof(out->unique.rsa.buffer)) {
out->unique.rsa.size =
(UINT16)sizeof(out->unique.rsa.buffer);
}
XMEMCPY(out->unique.rsa.buffer,
in->unique.rsa.buffer,
out->unique.rsa.size);
break;
case TPM_ALG_ECC:
wolfTPM2_CopySymmetric(&out->parameters.eccDetail.symmetric,
&in->parameters.eccDetail.symmetric);
out->parameters.eccDetail.scheme.scheme =
in->parameters.eccDetail.scheme.scheme;
out->parameters.eccDetail.scheme.details.any.hashAlg =
in->parameters.eccDetail.scheme.details.any.hashAlg;
out->parameters.eccDetail.curveID =
in->parameters.eccDetail.curveID;
out->parameters.eccDetail.kdf.scheme =
in->parameters.eccDetail.kdf.scheme;
out->parameters.eccDetail.kdf.details.any.hashAlg =
in->parameters.eccDetail.kdf.details.any.hashAlg;
wolfTPM2_CopyEccParam(&out->unique.ecc.x,
&in->unique.ecc.x);
wolfTPM2_CopyEccParam(&out->unique.ecc.y,
&in->unique.ecc.y);
break;
default:
wolfTPM2_CopySymmetric(&out->parameters.asymDetail.symmetric,
&in->parameters.asymDetail.symmetric);
out->parameters.asymDetail.scheme.scheme =
in->parameters.asymDetail.scheme.scheme;
out->parameters.asymDetail.scheme.details.anySig.hashAlg =
in->parameters.asymDetail.scheme.details.anySig.hashAlg;
break;
}
}
static void wolfTPM2_CopyPub(TPM2B_PUBLIC* out, const TPM2B_PUBLIC* in)
{
if (out != NULL && in != NULL) {
out->size = in->size;
wolfTPM2_CopyPubT(&out->publicArea, &in->publicArea);
}
}
static void wolfTPM2_CopyPriv(TPM2B_PRIVATE* out, const TPM2B_PRIVATE* in)
{
if (out != NULL && in != NULL) {
out->size = in->size;
if (out->size > (UINT16)sizeof(out->buffer))
out->size = (UINT16)sizeof(out->buffer);
XMEMCPY(out->buffer, in->buffer, out->size);
}
}
static void wolfTPM2_CopyEccParam(TPM2B_ECC_PARAMETER* out,
const TPM2B_ECC_PARAMETER* in)
{
if (out != NULL && in != NULL) {
out->size = in->size;
if (out->size > (UINT16)sizeof(out->buffer))
out->size = (UINT16)sizeof(out->buffer);
XMEMCPY(out->buffer, in->buffer, out->size);
}
}
static void wolfTPM2_CopyKeyFromBlob(WOLFTPM2_KEY* key, const WOLFTPM2_KEYBLOB* keyBlob)
{
if (key != NULL && keyBlob != NULL) {
key->handle.hndl = keyBlob->handle.hndl;
wolfTPM2_CopyAuth(&key->handle.auth, &keyBlob->handle.auth);
wolfTPM2_CopyName(&key->handle.name, &keyBlob->handle.name);
wolfTPM2_CopySymmetric(&key->handle.symmetric, &keyBlob->handle.symmetric);
wolfTPM2_CopyPub(&key->pub, &keyBlob->pub);
}
}
static void wolfTPM2_CopyNvPublic(TPMS_NV_PUBLIC* out, const TPMS_NV_PUBLIC* in)
{
if (out != NULL && in != NULL) {
out->attributes = in->attributes;
out->authPolicy.size = in->authPolicy.size;
if (out->authPolicy.size > 0) {
if (out->authPolicy.size > (UINT16)sizeof(out->authPolicy.buffer)) {
out->authPolicy.size = (UINT16)sizeof(out->authPolicy.buffer);
}
XMEMCPY(out->authPolicy.buffer, in->authPolicy.buffer, out->authPolicy.size);
}
out->dataSize = in->dataSize;
out->nameAlg = in->nameAlg;
out->nvIndex = in->nvIndex;
}
}
/******************************************************************************/
/* --- END Utility Functions -- */
/******************************************************************************/
/******************************************************************************/
/* --- BEGIN Certificate Signing Request (CSR) Functions -- */
/******************************************************************************/
#if defined(WOLFTPM2_CERT_GEN) && defined(WOLFTPM_CRYPTOCB)
/* Distinguished Name Strings */
typedef struct DNTags {
const char* tag;
size_t certNameOff;
} DNTags;
static int CSR_Parse_DN(CertName* name, const char* subject)
{
int rc = 0, i;
const DNTags tags[] = {
{"/CN=", OFFSETOF(CertName, commonName)}, /* Common Name */
{"/C=", OFFSETOF(CertName, country)}, /* Country */
{"/ST=", OFFSETOF(CertName, state)}, /* State */
{"/street=", OFFSETOF(CertName, street)}, /* Street */
{"/L=", OFFSETOF(CertName, locality)}, /* Locality */
{"/SN=", OFFSETOF(CertName, sur)}, /* Surname */
{"/O=", OFFSETOF(CertName, org)}, /* Organization */
{"/OU=", OFFSETOF(CertName, unit)}, /* Organization Unit */
{"/postalCode=", OFFSETOF(CertName, postalCode)}, /* PostalCode */
{"/userid=", OFFSETOF(CertName, userId)}, /* UserID */
{"/serialNumber=", OFFSETOF(CertName, serialDev)}, /* Serial Number */
{"/emailAddress=", OFFSETOF(CertName, email)}, /* Email Address */
#ifdef WOLFSSL_CERT_EXT
{"/businessCategory=", OFFSETOF(CertName, busCat)}, /* Business Category */
#endif
};
for (i = 0; i < (int)(sizeof(tags) / sizeof(DNTags)); i++) {
const char *begin, *end;
word32 len = 0;
/* find start tag */
begin = XSTRSTR(subject, tags[i].tag);
if (begin != NULL) {
/* find end of string or / */
begin += XSTRLEN(tags[i].tag);
end = XSTRSTR(begin, "/");
if (end == NULL) {
end = begin + XSTRLEN(begin); /* remainder of string */
}
if (end > begin) {
len = (word32)(size_t)(end - begin);
}
if (len > CTC_NAME_SIZE-1) {
len = CTC_NAME_SIZE-1; /* leave room for null term */
}
XMEMCPY((byte*)name + tags[i].certNameOff, begin, len);
}
}
return rc;
}
typedef struct CSRKey {
int keyType;
int tpmDevId;
WOLFTPM2_KEY* tpmKey;
union {
#ifndef NO_RSA
RsaKey rsa;
#endif
#ifdef HAVE_ECC
ecc_key ecc;
#endif
} key;
TpmCryptoDevCtx tpmCtx;
} CSRKey;
static int CSR_MakeAndSign(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr, CSRKey* key,
int outFormat, byte* out, int outSz, int selfSignCert)
{
int rc = 0;
if (dev == NULL || csr == NULL || key == NULL || out == NULL) {
return BAD_FUNC_ARG;
}
if (rc == 0 && selfSignCert) {
#ifdef WOLFSSL_CERT_GEN
rc = wc_MakeCert_ex(&csr->req, out, outSz, key->keyType, &key->key,
wolfTPM2_GetRng(dev));
#else
rc = NOT_COMPILED_IN;
#endif
}
if (rc == 0 && !selfSignCert) {
rc = wc_MakeCertReq_ex(&csr->req, out, outSz, key->keyType, &key->key);
}
if (rc >= 0) {
rc = wc_SignCert_ex(csr->req.bodySz, csr->req.sigType, out,
(word32)outSz, key->keyType, &key->key, wolfTPM2_GetRng(dev));
}
/* Optionally convert to PEM */
if (rc >= 0 && outFormat == CTC_FILETYPE_PEM) {
#ifdef WOLFSSL_DER_TO_PEM
WOLFTPM2_BUFFER tmp;
tmp.size = rc;
if (rc > (int)sizeof(tmp.buffer)) {
rc = BUFFER_E;
}
else {
XMEMCPY(tmp.buffer, out, rc);
XMEMSET(out, 0, outSz);
rc = wc_DerToPem(tmp.buffer, tmp.size, out, outSz,
selfSignCert ? CERT_TYPE : CERTREQ_TYPE);
}
#else
#ifdef DEBUG_WOLFTPM
printf("CSR_MakeAndSign PEM not supported\n")
#endif
rc = NOT_COMPILED_IN;
#endif
}
return rc;
}
static int CSR_KeySetup(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr, WOLFTPM2_KEY* key,
CSRKey* csrKey, int sigType, int devId)
{
int rc;
if (dev == NULL || key == NULL || csrKey == NULL) {
return BAD_FUNC_ARG;
}
XMEMSET(csrKey, 0, sizeof(CSRKey));
csrKey->tpmDevId = INVALID_DEVID;
csrKey->tpmKey = key;
/* confirm crypto callback is setup */
if (devId == INVALID_DEVID) {
/* Setup the wolf crypto device callback */
#ifndef NO_RSA
csrKey->tpmCtx.rsaKey = key;
#endif
#ifdef HAVE_ECC
csrKey->tpmCtx.eccKey = key;
#endif
rc = wolfTPM2_GetTpmDevId(dev);
if (rc >= 0) {
devId = rc;
devId += 1; /* use a different devId for the CSR callback */
rc = 0;
}
if (rc == 0) {
csrKey->tpmCtx.dev = dev;
rc = wc_CryptoCb_RegisterDevice(devId, wolfTPM2_CryptoDevCb,
&csrKey->tpmCtx);
}
if (rc != 0) {
return rc;
}
csrKey->tpmDevId = devId;
}
/* determine the type of key in WOLFTPM2_KEY */
if (key->pub.publicArea.type == TPM_ALG_ECC) {
csrKey->keyType = ECC_TYPE;
#ifdef HAVE_ECC
/* setup wolf ECC key with TPM deviceID, so crypto callbacks are used */
rc = wc_ecc_init_ex(&csrKey->key.ecc, NULL, devId);
if (rc == 0) {
/* load public portion of key into wolf ECC Key */
rc = wolfTPM2_EccKey_TpmToWolf(dev, key, &csrKey->key.ecc);
}
#else
rc = NOT_COMPILED_IN;
#endif
}
else if (key->pub.publicArea.type == TPM_ALG_RSA) {
csrKey->keyType = RSA_TYPE;
#ifndef NO_RSA
/* setup wolf RSA key with TPM deviceID, so crypto callbacks are used */
rc = wc_InitRsaKey_ex(&csrKey->key.rsa, NULL, devId);
if (rc == 0) {
/* load public portion of key into wolf RSA Key */
rc = wolfTPM2_RsaKey_TpmToWolf(dev, key, &csrKey->key.rsa);
}
#else
rc = NOT_COMPILED_IN;
#endif
}
else {
#ifdef DEBUG_WOLFTPM
printf("CSR_KeySetup invalid input key\n");
#endif
rc = BAD_FUNC_ARG;
}
/* Set the signature type */
if (rc == 0) {
if (sigType == 0 && csrKey != NULL) {
/* Choose defaults if sigType is zero */
if (csrKey->keyType == RSA_TYPE) {
csr->req.sigType = CTC_SHA256wRSA;
}
else if (csrKey->keyType == ECC_TYPE) {
csr->req.sigType = CTC_SHA256wECDSA;
}
}
else if (sigType != 0) {
csr->req.sigType = sigType;
}
}
#ifdef WOLFSSL_CERT_EXT
/* add SKID from the Public Key */
if (rc == 0 && csrKey != NULL) {
rc = wc_SetSubjectKeyIdFromPublicKey_ex(&csr->req, csrKey->keyType,
&csrKey->key);
}
#endif
return rc;
}
static void CSR_KeyCleanup(WOLFTPM2_DEV* dev, CSRKey* csrKey)
{
if (dev != NULL && csrKey != NULL) {
#ifdef HAVE_ECC
if (csrKey->keyType == ECC_TYPE) {
wc_ecc_free(&csrKey->key.ecc);
}
#endif
#ifndef NO_RSA
if (csrKey->keyType == RSA_TYPE) {
wc_FreeRsaKey(&csrKey->key.rsa);
}
#endif
if (csrKey->tpmDevId != INVALID_DEVID) {
wolfTPM2_ClearCryptoDevCb(dev, csrKey->tpmDevId);
}
}
}
int wolfTPM2_CSR_SetCustomExt(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr,
int critical, const char *oid, const byte *der, word32 derSz)
{
int rc;
if (csr == NULL) {
return BAD_FUNC_ARG;
}
#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_CUSTOM_OID) && \
defined(HAVE_OID_ENCODING)
rc = wc_SetCustomExtension(&csr->req, critical, oid, der, derSz);
#else
(void)critical;
(void)oid;
(void)der;
(void)derSz;
/* Requires:
* ./configure --enable-wolftpm --enable-certgen --enable-asn=template \
CFLAGS="-DWOLFSSL_CUSTOM_OID -DHAVE_OID_ENCODING"
*/
rc = NOT_COMPILED_IN;
#endif
(void)dev; /* not used */
return rc;
}
int wolfTPM2_CSR_SetSubject(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr,
const char* subject)
{
int rc = BAD_FUNC_ARG;
if (csr != NULL && subject != NULL) {
rc = CSR_Parse_DN(&csr->req.subject, subject);
}
(void)dev; /* not used */
return rc;
}
int wolfTPM2_CSR_SetKeyUsage(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr,
const char* keyUsage)
{
int rc;
if (csr == NULL) {
return BAD_FUNC_ARG;
}
#ifdef WOLFSSL_CERT_EXT
if (keyUsage == NULL) {
/* use a default key usage value */
keyUsage = "serverAuth,clientAuth,codeSigning";
}
/* add Extended Key Usage */
rc = wc_SetExtKeyUsage(&csr->req, keyUsage);
if (rc == EXTKEYUSAGE_E) {
/* try setting key usage values */
rc = wc_SetKeyUsage(&csr->req, keyUsage);
}
#else
if (keyUsage != NULL) {
#ifdef DEBUG_WOLFTPM
printf("CSR_Generate key usage supplied, but not available\n");
#endif
rc = NOT_COMPILED_IN;
}
#endif
(void)dev; /* not used */
return rc;
}
int wolfTPM2_CSR_MakeAndSign_ex(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr,
WOLFTPM2_KEY* key, int outFormat, byte* out, int outSz,
int sigType, int selfSignCert, int devId)
{
int rc;
CSRKey csrKey;
if (dev == NULL || key == NULL || csr == NULL || out == NULL) {
return BAD_FUNC_ARG;
}
rc = CSR_KeySetup(dev, csr, key, &csrKey, sigType, devId);
if (rc == 0) {
rc = CSR_MakeAndSign(dev, csr, &csrKey, outFormat, out, outSz,
selfSignCert);
}
CSR_KeyCleanup(dev, &csrKey);
return rc;
}
int wolfTPM2_CSR_MakeAndSign(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr,
WOLFTPM2_KEY* key, int outFormat, byte* out, int outSz)
{
return wolfTPM2_CSR_MakeAndSign_ex(dev, csr, key, outFormat, out, outSz,
0, 0, INVALID_DEVID);
}
int wolfTPM2_CSR_Generate_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
const char* subject, const char* keyUsage, int outFormat,
byte* out, int outSz, int sigType, int selfSignCert, int devId)
{
int rc;
WOLFTPM2_CSR csr;
CSRKey csrKey;
if (dev == NULL || key == NULL || subject == NULL || out == NULL) {
return BAD_FUNC_ARG;
}
XMEMSET(&csrKey, 0, sizeof(csrKey));
rc = wc_InitCert(&csr.req);
if (rc == 0) {
rc = CSR_KeySetup(dev, &csr, key, &csrKey, sigType, devId);
}
if (rc == 0) {
rc = wolfTPM2_CSR_SetSubject(dev, &csr, subject);
}
if (rc == 0) {
rc = wolfTPM2_CSR_SetKeyUsage(dev, &csr, keyUsage);
}
if (rc == 0) {
rc = CSR_MakeAndSign(dev, &csr, &csrKey, outFormat, out, outSz,
selfSignCert);
}
CSR_KeyCleanup(dev, &csrKey);
return rc;
}
int wolfTPM2_CSR_Generate(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
const char* subject, const char* keyUsage, int outFormat,
byte* out, int outSz)
{
return wolfTPM2_CSR_Generate_ex(dev, key, subject, keyUsage, outFormat,
out, outSz, 0, 0, INVALID_DEVID);
}
#endif /* WOLFTPM2_CERT_GEN && WOLFTPM_CRYPTOCB */
/******************************************************************************/
/* --- END Certificate Signing Request (CSR) Functions -- */
/******************************************************************************/
/******************************************************************************/
/* --- BEGIN Policy Support -- */
/******************************************************************************/
int wolfTPM2_PolicyRestart(WOLFTPM2_DEV* dev, TPM_HANDLE sessionHandle)
{
int rc;
PolicyRestart_In policyRestartIn[1];
if (dev == NULL)
return BAD_FUNC_ARG;
XMEMSET(policyRestartIn, 0, sizeof(PolicyRestart_In));
policyRestartIn->sessionHandle = sessionHandle;
rc = TPM2_PolicyRestart(policyRestartIn);
return rc;
}
int wolfTPM2_GetPolicyDigest(WOLFTPM2_DEV* dev, TPM_HANDLE sessionHandle,
byte* policyDigest, word32* policyDigestSz)
{
int rc;
PolicyGetDigest_In policyGetDigestIn[1];
PolicyGetDigest_Out policyGetDigestOut[1];
if (dev == NULL || policyDigestSz == NULL)
return BAD_FUNC_ARG;
XMEMSET(policyGetDigestIn, 0, sizeof(PolicyGetDigest_In));
XMEMSET(policyGetDigestOut, 0, sizeof(PolicyGetDigest_Out));
policyGetDigestIn->policySession = sessionHandle;
rc = TPM2_PolicyGetDigest(policyGetDigestIn, policyGetDigestOut);
if (rc == 0) {
if (policyDigest == NULL) {
rc = LENGTH_ONLY_E;
}
else if (policyGetDigestOut->policyDigest.size > *policyDigestSz) {
rc = BUFFER_E;
}
else {
XMEMCPY(policyDigest, policyGetDigestOut->policyDigest.buffer,
policyGetDigestOut->policyDigest.size);
}
*policyDigestSz = policyGetDigestOut->policyDigest.size;
}
return rc;
}
int wolfTPM2_PolicyPCR(WOLFTPM2_DEV* dev, TPM_HANDLE sessionHandle,
TPM_ALG_ID pcrAlg, byte* pcrArray, word32 pcrArraySz)
{
int rc;
PolicyPCR_In policyPcr[1];
if (dev == NULL || pcrArray == NULL || pcrArraySz == 0)
return BAD_FUNC_ARG;
XMEMSET(policyPcr, 0, sizeof(PolicyPCR_In));
/* add PolicyPCR to the policy */
policyPcr->policySession = sessionHandle;
TPM2_SetupPCRSelArray(&policyPcr->pcrs, pcrAlg, pcrArray, pcrArraySz);
rc = TPM2_PolicyPCR(policyPcr);
return rc;
}
#ifndef WOLFTPM2_NO_WOLFCRYPT
/* Authorize a policy based on external key for a verified policy digiest signature */
int wolfTPM2_PolicyAuthorize(WOLFTPM2_DEV* dev, TPM_HANDLE sessionHandle,
const TPM2B_PUBLIC* pub, const TPMT_TK_VERIFIED* checkTicket,
const byte* pcrDigest, word32 pcrDigestSz,
const byte* policyRef, word32 policyRefSz)
{
int rc;
PolicyAuthorize_In policyAuthIn;
if (dev == NULL || pub == NULL || checkTicket == NULL || pcrDigest == NULL) {
return BAD_FUNC_ARG;
}
XMEMSET(&policyAuthIn, 0, sizeof(policyAuthIn));
policyAuthIn.policySession = sessionHandle;
XMEMCPY(&policyAuthIn.checkTicket, checkTicket, sizeof(TPMT_TK_VERIFIED));
/* set the approved policy digest */
policyAuthIn.approvedPolicy.size = pcrDigestSz;
XMEMCPY(policyAuthIn.approvedPolicy.buffer, pcrDigest, pcrDigestSz);
/* policyRef (nonce) */
policyAuthIn.policyRef.size = policyRefSz;
if (policyRef != NULL) {
XMEMCPY(policyAuthIn.policyRef.buffer, policyRef, policyRefSz);
}
/* Compute name for the authoring public key for policy */
rc = wolfTPM2_ComputeName(pub, &policyAuthIn.keySign);
if (rc == TPM_RC_SUCCESS) {
rc = TPM2_PolicyAuthorize(&policyAuthIn);
}
#ifdef DEBUG_WOLFTPM
if (rc != TPM_RC_SUCCESS) {
printf("PolicyAuthorize failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
}
#endif
return rc;
}
/* Build Hash of PCR's */
int wolfTPM2_PCRGetDigest(WOLFTPM2_DEV* dev, TPM_ALG_ID pcrAlg,
byte* pcrArray, word32 pcrArraySz, byte* pcrDigest, word32* pcrDigestSz)
{
int rc;
word32 i;
enum wc_HashType hashType;
wc_HashAlg hash_ctx;
if (dev == NULL || pcrArray == NULL || pcrArraySz == 0 ||
pcrDigest == NULL || pcrDigestSz == NULL) {
return BAD_FUNC_ARG;
}
rc = TPM2_GetHashType(pcrAlg);
hashType = (enum wc_HashType)rc;
rc = wc_HashGetDigestSize(hashType);
if (rc < 0)
return rc;
*pcrDigestSz = rc; /* set actual size */
rc = wc_HashInit(&hash_ctx, hashType);
if (rc != 0)
return rc;
/* PCR(s) hash */
for (i=0; i<pcrArraySz && rc == 0; i++) {
rc = wolfTPM2_ReadPCR(dev, pcrArray[i], pcrAlg,
pcrDigest, (int*)pcrDigestSz);
if (rc == 0) {
rc = wc_HashUpdate(&hash_ctx, hashType, pcrDigest, *pcrDigestSz);
}
}
if (rc == 0) {
rc = wc_HashFinal(&hash_ctx, hashType, pcrDigest);
}
wc_HashFree(&hash_ctx, hashType);
#ifdef DEBUG_WOLFTPM
if (rc != 0) {
printf("wolfTPM2_PCRGetDigest failed %d: %s\n",
rc, wolfTPM2_GetRCString(rc));
}
#ifdef WOLFTPM_DEBUG_VERBOSE
else {
printf("wolfTPM2_PCRGetDigest: %d\n", *pcrDigestSz);
TPM2_PrintBin(pcrDigest, *pcrDigestSz);
}
#endif
#endif
return rc;
}
/* Assemble a PCR policy */
/* policyDigestnew = hash(policyDigestOld || TPM_CC_PolicyPCR || PCRS ||
* pcrDigest) */
int wolfTPM2_PolicyPCRMake(TPM_ALG_ID pcrAlg, byte* pcrArray, word32 pcrArraySz,
const byte* pcrDigest, word32 pcrDigestSz, byte* digest, word32* digestSz)
{
int rc;
word32 val;
enum wc_HashType hashType;
wc_HashAlg hash_ctx;
word32 inSz;
if (pcrArray == NULL || pcrArraySz == 0 || digest == NULL ||
digestSz == NULL) {
return BAD_FUNC_ARG;
}
inSz = *digestSz; /* capture input digest size (for policyDigestOld) */
rc = TPM2_GetHashType(pcrAlg);
hashType = (enum wc_HashType)rc;
rc = wc_HashGetDigestSize(hashType);
if (rc < 0)
return rc;
*digestSz = rc; /* set actual size */
rc = wc_HashInit(&hash_ctx, hashType);
if (rc != 0)
return rc;
/* policyDigestOld */
if (rc == 0 && inSz > 0) {
rc = wc_HashUpdate(&hash_ctx, hashType, digest, inSz);
}
/* Command Code */
if (rc == 0) {
val = TPM2_Packet_SwapU32(TPM_CC_PolicyPCR);
rc = wc_HashUpdate(&hash_ctx, hashType, (byte*)&val, sizeof(val));
}
/* PCR Count and PCR Selection */
if (rc == 0) {
TPM2_Packet packet;
byte buf[sizeof(TPML_PCR_SELECTION)];
TPML_PCR_SELECTION pcr;
XMEMSET(&pcr, 0, sizeof(pcr));
XMEMSET(&packet, 0, sizeof(packet));
TPM2_SetupPCRSelArray(&pcr, pcrAlg, pcrArray, pcrArraySz);
packet.buf = buf;
packet.size = sizeof(buf);
TPM2_Packet_AppendPCR(&packet, &pcr);
rc = wc_HashUpdate(&hash_ctx, hashType, buf, packet.pos);
}
/* Hash of PCR(s) */
if (rc == 0) {
rc = wc_HashUpdate(&hash_ctx, hashType, pcrDigest, pcrDigestSz);
}
if (rc == 0) {
rc = wc_HashFinal(&hash_ctx, hashType, digest);
}
wc_HashFree(&hash_ctx, hashType);
#ifdef DEBUG_WOLFTPM
if (rc != 0) {
printf("wolfTPM2_PolicyPCRMake failed %d: %s\n",
rc, wolfTPM2_GetRCString(rc));
}
#ifdef WOLFTPM_DEBUG_VERBOSE
else {
printf("wolfTPM2_PolicyPCRMake: %d\n", *digestSz);
TPM2_PrintBin(digest, *digestSz);
}
#endif
#endif
return rc;
}
/* Assemble a PCR policy ref - optional */
/* aHash = hash(approvedPolicy || policyRef) */
int wolfTPM2_PolicyRefMake(TPM_ALG_ID pcrAlg, byte* digest, word32* digestSz,
const byte* policyRef, word32 policyRefSz)
{
int rc;
enum wc_HashType hashType;
wc_HashAlg hash_ctx;
word32 inSz;
if (digest == NULL || digestSz == NULL ||
(policyRef == NULL && policyRefSz > 0)) {
return BAD_FUNC_ARG;
}
inSz = *digestSz; /* capture input digest size (for approvedPolicy) */
rc = TPM2_GetHashType(pcrAlg);
hashType = (enum wc_HashType)rc;
rc = wc_HashGetDigestSize(hashType);
if (rc < 0)
return rc;
*digestSz = rc; /* set actual size */
rc = wc_HashInit(&hash_ctx, hashType);
if (rc != 0)
return rc;
/* approvedPolicy */
if (rc == 0 && inSz > 0) {
rc = wc_HashUpdate(&hash_ctx, hashType, digest, inSz);
}
/* policyRef */
if (rc == 0 && policyRefSz > 0) {
rc = wc_HashUpdate(&hash_ctx, hashType, policyRef, policyRefSz);
}
if (rc == 0) {
rc = wc_HashFinal(&hash_ctx, hashType, digest);
}
wc_HashFree(&hash_ctx, hashType);
#ifdef DEBUG_WOLFTPM
if (rc != 0) {
printf("wolfTPM_PolicyRefMake failed %d: %s\n",
rc, wolfTPM2_GetRCString(rc));
}
#ifdef WOLFTPM_DEBUG_VERBOSE
else {
printf("wolfTPM_PolicyRefMake: %d\n", *digestSz);
TPM2_PrintBin(digest, *digestSz);
}
#endif
#endif
return rc;
}
/* Assemble a PCR Authorization for a public key */
/* policyDigestnew = hash(policyDigestOld || TPM_CC_PolicyAuthorize ||
* Public.Name || PolicyRef) */
int wolfTPM2_PolicyAuthorizeMake(TPM_ALG_ID pcrAlg,
const TPM2B_PUBLIC* pub, byte* digest, word32* digestSz,
const byte* policyRef, word32 policyRefSz)
{
int rc;
word32 val;
enum wc_HashType hashType;
wc_HashAlg hash_ctx;
word32 inSz;
if (pub == NULL || digest == NULL || digestSz == NULL) {
return BAD_FUNC_ARG;
}
inSz = *digestSz; /* capture input digest size (for policyDigestOld) */
rc = TPM2_GetHashType(pcrAlg);
hashType = (enum wc_HashType)rc;
rc = wc_HashGetDigestSize(hashType);
if (rc < 0)
return rc;
*digestSz = rc;
rc = wc_HashInit(&hash_ctx, hashType);
if (rc != 0)
return rc;
/* policyDigestOld */
if (rc == 0 && inSz > 0) {
rc = wc_HashUpdate(&hash_ctx, hashType, digest, inSz);
}
/* Command Code */
if (rc == 0) {
val = TPM2_Packet_SwapU32(TPM_CC_PolicyAuthorize);
rc = wc_HashUpdate(&hash_ctx, hashType, (byte*)&val, sizeof(val));
}
/* Public Name Compute */
if (rc == 0) {
TPM2B_NAME name;
rc = wolfTPM2_ComputeName(pub, &name);
if (rc == 0) {
rc = wc_HashUpdate(&hash_ctx, hashType, name.name, name.size);
}
}
if (rc == 0) {
rc = wc_HashFinal(&hash_ctx, hashType, digest);
}
wc_HashFree(&hash_ctx, hashType);
if (rc == 0) {
rc = wolfTPM2_PolicyRefMake(pcrAlg, digest, digestSz,
policyRef, policyRefSz);
}
#ifdef DEBUG_WOLFTPM
if (rc != 0) {
printf("wolfTPM2_PolicyAuthorizeMake failed %d: %s\n",
rc, wolfTPM2_GetRCString(rc));
}
#ifdef WOLFTPM_DEBUG_VERBOSE
else {
printf("wolfTPM2_PolicyAuthorizeMake: %d\n", *digestSz);
TPM2_PrintBin(digest, *digestSz);
}
#endif
#endif
return rc;
}
#endif /* !WOLFTPM2_NO_WOLFCRYPT */
/******************************************************************************/
/* --- END Policy Support -- */
/******************************************************************************/
#endif /* !WOLFTPM2_NO_WRAPPER */