wolfTPM/src/tpm2_wrap.c

4388 lines
135 KiB
C

/* tpm2_wrap.c
*
* Copyright (C) 2006-2020 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_WOLFCRYPT
#include <wolfssl/wolfcrypt/aes.h>
#include <wolfssl/wolfcrypt/hmac.h>
#endif
#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);
/******************************************************************************/
/* --- 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_MCHP) || 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_MCHP) || 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_MCHP || WOLFTPM_PERFORM_SELFTEST */
#endif /* !defined(WOLFTPM_LINUX_DEV) && !defined(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_SetAuth(dev, 0, TPM_RS_PW, NULL, 0);
return rc;
}
/* 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_SetAuth(dev, 0, TPM_RS_PW, NULL, 0);
return rc;
}
int wolfTPM2_GetTpmDevId(WOLFTPM2_DEV* dev)
{
if (dev == NULL) {
return BAD_FUNC_ARG;
}
return 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);
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->mfg == TPM_MFG_NUVOTON) {
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_SetAuth(WOLFTPM2_DEV* dev, int index,
TPM_HANDLE sessionHandle, const byte* auth, int authSz)
{
if (dev == NULL || index >= MAX_SESSION_NUM) {
return BAD_FUNC_ARG;
}
/* define the default session auth */
XMEMSET(&dev->session[index], 0, sizeof(dev->session[index]));
dev->session[index].sessionHandle = sessionHandle;
dev->session[index].auth.size = authSz;
if (auth && authSz > 0)
XMEMCPY(dev->session[index].auth.buffer, auth, authSz);
TPM2_SetSessionAuth(dev->session);
return 0;
}
int wolfTPM2_Cleanup_ex(WOLFTPM2_DEV* dev, int doShutdown)
{
int rc = 0;
if (dev == NULL) {
return BAD_FUNC_ARG;
}
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && (defined(WOLF_CRYPTO_DEV) || defined(WOLF_CRYPTO_CB))
/* 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
}
#ifndef WOLFTPM2_NO_WOLFCRYPT
#ifndef NO_RSA
/* returns both the plaintext and encrypted salt, based on the salt key bPublic. */
static int wolfTPM2_RSA_Salt(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* tpmKey,
TPM2B_DIGEST *salt, TPM2B_ENCRYPTED_SECRET *encSalt, TPMT_PUBLIC *publicArea)
{
int rc;
WC_RNG* rng;
enum wc_HashType hashType;
const char* label = "SECRET";
int mgf;
RsaKey rsaKey;
if (dev == NULL || salt == NULL || encSalt == NULL || publicArea == NULL) {
return BAD_FUNC_ARG;
}
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;
}
rc = TPM2_GetWolfRng(&rng);
if (rc != TPM_RC_SUCCESS)
return rc;
rc = wc_InitRsaKey_ex(&rsaKey, NULL, INVALID_DEVID);
if (rc != 0) {
return rc;
}
wc_RsaSetRNG(&rsaKey, rng);
rc = wolfTPM2_RsaKey_TpmToWolf(dev, tpmKey, &rsaKey);
if (rc != 0) {
wc_FreeRsaKey(&rsaKey);
return rc;
}
encSalt->size = publicArea->unique.rsa.size;
rc = wc_RsaPublicEncrypt_ex(
salt->buffer, /* in pointer to the buffer for encryption */
salt->size, /* inLen length of in parameter */
encSalt->secret, /* out encrypted msg created */
encSalt->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);
if (rc != encSalt->size) {
return BUFFER_E;
}
return 0;
}
#endif /* !NO_RSA */
static int wolfTPM2_EncryptSalt(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* tpmKey,
StartAuthSession_In* in, const char* bindPassword, TPM2B_DIGEST* salt)
{
int rc;
/* if a tpmKey is present then we are using a salted session */
if (tpmKey == NULL) {
return TPM_RC_SUCCESS;
}
/* generate a salt */
salt->size = TPM2_GetHashDigestSize(in->authHash);
if (salt->size <= 0) {
return TPM_RC_FAILURE;
}
rc = TPM2_GetNonce(salt->buffer, salt->size);
if (rc != 0) {
return rc;
}
switch (tpmKey->pub.publicArea.type) {
#ifdef HAVE_ECC
case TPM_ALG_ECC:
/* TODO: */
rc = NOT_COMPILED_IN;
break;
#endif
#ifndef NO_RSA
case TPM_ALG_RSA:
rc = wolfTPM2_RSA_Salt(dev, tpmKey, salt, &in->encryptedSalt,
&tpmKey->pub.publicArea);
break;
#endif
default:
rc = NOT_COMPILED_IN;
break;
}
(void)bindPassword; /* TODO: Add bind support */
return rc;
}
#endif /* !WOLFTPM2_NO_WOLFCRYPT */
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;
if (dev == NULL || session == NULL)
return BAD_FUNC_ARG;
XMEMSET(&authSesIn, 0, sizeof(authSesIn));
authSesIn.tpmKey = tpmKey ? tpmKey->handle.hndl :
(TPMI_DH_OBJECT)TPM_RH_NULL;
authSesIn.bind = bind ? bind->hndl : (TPMI_DH_ENTITY)TPM_RH_NULL;
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.authHash = WOLFTPM2_WRAP_DIGEST;
authSesIn.nonceCaller.size = TPM2_GetHashDigestSize(WOLFTPM2_WRAP_DIGEST);
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;
}
#ifndef WOLFTPM2_NO_WOLFCRYPT
/* Generate and Encrypt salt using "SECRET" */
rc = wolfTPM2_EncryptSalt(dev, tpmKey, &authSesIn, session->bindPassword,
&session->salt);
if (rc != 0) {
#ifdef DEBUG_WOLFTPM
printf("Building encrypted salt failed %d: %s!\n", rc,
wolfTPM2_GetRCString(rc));
#endif
}
#endif
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;
}
session->handle.hndl = authSesOut.sessionHandle;
session->nonceTPM = authSesOut.nonceTPM;
#ifdef DEBUG_WOLFTPM
printf("TPM2_StartAuthSession: handle 0x%x\n",
(word32)session->handle.hndl);
#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;
/* 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;
key->handle.auth = createPriIn.inSensitive.sensitive.userAuth;
key->pub = createPriOut.outPublic;
key->name = createPriOut.name;
#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 */
dev->session[0].auth = key->handle.auth;
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
return rc;
}
/* unload old key */
wolfTPM2_UnloadHandle(dev, &key->handle);
/* set session auth for parent key */
dev->session[0].auth = parent->auth;
/* Load new key */
XMEMSET(&loadIn, 0, sizeof(loadIn));
loadIn.parentHandle = parent->hndl;
loadIn.inPrivate = changeOut.outPrivate;
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
return rc;
}
key->handle.hndl = loadOut.objectHandle;
key->handle.auth = changeIn.newAuth;
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_ChangeAuthKey: Key Handle 0x%x\n", (word32)key->handle.hndl);
#endif
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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));
/* set session auth for key */
dev->session[0].auth = parent->auth;
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
return rc;
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_Create key: pub %d, priv %d\n", createOut.outPublic.size,
createOut.outPrivate.size);
printf("save\n");
TPM2_PrintBin(createOut.outPrivate.buffer, createOut.outPrivate.size);
#endif
keyBlob->handle.auth = createIn.inSensitive.sensitive.userAuth;
keyBlob->pub = createOut.outPublic;
keyBlob->priv = createOut.outPrivate;
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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 key */
dev->session[0].auth = parent->auth;
/* Load new key */
XMEMSET(&loadIn, 0, sizeof(loadIn));
loadIn.parentHandle = parent->hndl;
loadIn.inPrivate = keyBlob->priv;
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
return rc;
}
keyBlob->handle.hndl = loadOut.objectHandle;
#ifdef DEBUG_WOLFTPM
printf("TPM2_Load Key Handle 0x%x\n", (word32)keyBlob->handle.hndl);
#endif
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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_LoadPublicKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
const TPM2B_PUBLIC* pub)
{
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));
loadExtIn.inPublic = *pub;
loadExtIn.hierarchy = TPM_RH_NULL;
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;
key->pub = loadExtIn.inPublic;
#ifdef DEBUG_WOLFTPM
printf("TPM2_LoadExternal: 0x%x\n", (word32)loadExtOut.objectHandle);
#endif
return rc;
}
int wolfTPM2_ComputeName(const TPM2B_PUBLIC* pub, TPM2B_NAME* out)
{
int rc;
TPMI_ALG_HASH nameAlg;
#ifndef WOLFTPM2_NO_WOLFCRYPT
TPM2_Packet packet;
TPM2B_DATA data;
wc_HashAlg hash;
enum wc_HashType hashType;
int hashSz;
#endif
if (pub == NULL || out == NULL)
return BAD_FUNC_ARG;
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_AppendPublic(&packet, (TPM2B_PUBLIC*)pub);
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 */
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_ENCRYPTED_SECRET* symSeed)
{
int innerWrap = 0;
int outerWrap = 0;
TPMI_ALG_HASH innerAlg, outerAlg;
TPM2_Packet packet;
int pos = 0;
int digestSz, innerSz, outerSz, sensSz;
TPM2B_IV ivField;
TPM2B_SYM_KEY symKey;
TPM2B_DIGEST hmacKey;
Aes enc;
Hmac hmac;
int rc;
if (sens == NULL || priv == NULL)
return BAD_FUNC_ARG;
digestSz = TPM2_GetHashDigestSize(nameAlg);
innerSz = outerSz = sensSz = 0;
if (sym && sym->algorithm != TPM_ALG_NULL) {
innerWrap = 1;
innerAlg = nameAlg;
innerSz = sizeof(word16) + digestSz;
pos += innerSz;
}
if (symSeed && symSeed->size > 0 && parentKey) {
outerWrap = 1;
outerAlg = parentKey->pub.publicArea.nameAlg;
outerSz = sizeof(word16) + TPM2_GetHashDigestSize(outerAlg);
pos += outerSz;
}
/* Encode sensitive into private buffer */
XMEMSET(&packet, 0, sizeof(packet));
packet.buf = &priv->buffer[pos];
packet.size = sizeof(priv->buffer) - pos;
TPM2_Packet_AppendSensitive(&packet, sens);
priv->size = packet.pos;
/* Calculate the size of the sensitive area for later use */
sensSz = packet.pos - innerSz - outerSz;
if (innerWrap) {
/* Generate IV */
ivField.size = digestSz;
rc = TPM2_GetNonce(ivField.buffer, ivField.size);
if (rc != 0)
return TPM_RC_FAILURE;
/* Generate symmetric key for encryption of inner values */
symKey.size = (sym->keyBits.sym + 7) / 8;
TPM2_KDFa(innerAlg, (TPM2B_DATA*)&sens->sensitiveArea.seedValue,
"STORAGE", (TPM2B_NONCE*)name, NULL,
symKey.buffer, symKey.size * 8);
/* 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.buffer, AES_ENCRYPTION);
if (rc == 0) {
/* Encryption in-place */
rc = wc_AesCfbEncrypt(&enc, &packet.buf[innerSz], &packet.buf[innerSz], sensSz);
}
wc_AesFree(&enc);
}
}
if (outerWrap) {
/* Generate HMAC key for generation of the integrity value */
hmacKey.size = TPM2_GetHashDigestSize(outerAlg);
TPM2_KDFa(outerAlg, (TPM2B_DATA*)&sens->sensitiveArea.seedValue,
"INTEGRITY", NULL, NULL,
hmacKey.buffer, hmacKey.size * 8);
/* setup HMAC */
rc = wc_HmacInit(&hmac, NULL, INVALID_DEVID);
if (rc != 0)
return rc;
/* start HMAC */
rc = wc_HmacSetKey(&hmac, outerAlg, hmacKey.buffer, hmacKey.size);
if (rc != 0)
return rc;
/* consume IV area */
rc = wc_HmacUpdate(&hmac, &packet.buf[outerSz], innerSz);
if (rc != 0)
return rc;
/* consume sensitive area */
rc = wc_HmacUpdate(&hmac, &packet.buf[innerSz], sensSz);
if (rc != 0)
return rc;
/* consume name field */
rc = wc_HmacUpdate(&hmac, name->name, name->size);
if (rc != 0)
return rc;
/* write result at position after Priv->size and Outer->Size field */
rc = wc_HmacFinal(&hmac, &packet.buf[sizeof(word16)+sizeof(word16)]);
if (rc != 0)
return rc;
/* store the size of the outer integrity in the Outer->Size field */
XMEMCPY(&packet.buf[sizeof(word16)], &hmacKey.size, sizeof(word16));
}
return 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;
if (dev == NULL || keyBlob == NULL || pub == NULL ||
sens == NULL) {
return BAD_FUNC_ARG;
}
/* set session auth for key */
if (parentKey != NULL) {
dev->session[0].auth = parentKey->handle.auth;
dev->session[0].symmetric =
parentKey->pub.publicArea.parameters.rsaDetail.symmetric;
parentHandle = parentKey->handle.hndl;
}
else {
parentHandle = TPM_RH_OWNER;
}
/* Import private key */
XMEMSET(&importIn, 0, sizeof(importIn));
importIn.parentHandle = parentHandle;
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
return rc;
}
rc = wolfTPM2_SensitiveToPrivate(sens, &importIn.duplicate,
pub->publicArea.nameAlg, &name, parentKey, &importIn.symmetricAlg,
&importIn.inSymSeed);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_SensitiveToPrivate: failed %d: %s\n", rc,
wolfTPM2_GetRCString(rc));
#endif
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
return rc;
}
keyBlob->pub = importIn.objectPublic;
keyBlob->priv = importOut.outPrivate;
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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 */
XMEMCPY(key, &keyBlob, sizeof(WOLFTPM2_KEY));
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;
pub.publicArea.nameAlg = TPM_ALG_NULL;
pub.publicArea.objectAttributes = (TPMA_OBJECT_sign | TPMA_OBJECT_decrypt |
TPMA_OBJECT_userWithAuth | TPMA_OBJECT_noDA);
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_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)
{
TPM2B_PUBLIC pub;
TPM2B_SENSITIVE sens;
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 = (TPMA_OBJECT_sign | TPMA_OBJECT_decrypt |
TPMA_OBJECT_userWithAuth | TPMA_OBJECT_noDA);
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);
/* 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);
return wolfTPM2_ImportPrivateKey(dev, parentKey, keyBlob, &pub, &sens);
}
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 */
XMEMCPY(key, &keyBlob, sizeof(WOLFTPM2_KEY));
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;
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_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)
{
TPM2B_PUBLIC pub;
TPM2B_SENSITIVE sens;
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 = TPMA_OBJECT_sign | TPMA_OBJECT_decrypt |
TPMA_OBJECT_userWithAuth | TPMA_OBJECT_noDA;
pub.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL;
pub.publicArea.parameters.eccDetail.scheme.scheme = 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 = 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);
return wolfTPM2_ImportPrivateKey(dev, parentKey, keyBlob, &pub, &sens);
}
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 */
XMEMCPY(key, &keyBlob, sizeof(WOLFTPM2_KEY));
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;
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_RSA
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;
}
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 */
rc = wc_RsaExportKey(wolfKey, e, &eSz, n, &nSz,
d, &dSz, p, &pSz, q, &qSz);
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);
}
#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(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;
if (parentKey && wolfKey->type == ECC_PRIVATEKEY) {
byte d[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
word32 dSz = sizeof(d);
XMEMSET(d, 0, sizeof(d));
/* 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;
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 ||
(primaryHandle != TPM_RH_OWNER && primaryHandle != TPM_RH_PLATFORM) ||
persistentHandle < PERSISTENT_FIRST ||
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;
/* 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 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;
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 || *sigSz < (curveSize * 2)) {
return BAD_FUNC_ARG;
}
}
else if (key->pub.publicArea.type == TPM_ALG_RSA) {
if (*sigSz < (int)sizeof(signOut.signature.signature.rsassa.sig.buffer)) {
return BAD_FUNC_ARG;
}
}
/* set session auth for key */
dev->session[0].auth = key->handle.auth;
dev->session[0].symmetric =
key->pub.publicArea.parameters.eccDetail.symmetric;
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
return rc;
}
if (key->pub.publicArea.type == TPM_ALG_ECC) {
/* Assemble R and S into signature (R then S) */
*sigSz = signOut.signature.signature.ecdsa.signatureR.size +
signOut.signature.signature.ecdsa.signatureS.size;
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) */
*sigSz = signOut.signature.signature.rsassa.sig.size;
XMEMCPY(sig, signOut.signature.signature.rsassa.sig.buffer,
signOut.signature.signature.rsassa.sig.size);
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_Sign: %s %d\n",
TPM2_GetAlgName(signIn.inScheme.scheme), *sigSz);
#endif
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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;
if (dev == NULL || key == NULL || digest == NULL || sig == NULL) {
return BAD_FUNC_ARG;
}
if (key->pub.publicArea.type == TPM_ALG_ECC) {
sigAlg = key->pub.publicArea.parameters.eccDetail.scheme.scheme;
}
else if (key->pub.publicArea.type == TPM_ALG_RSA) {
sigAlg = key->pub.publicArea.parameters.rsaDetail.scheme.scheme;
}
return wolfTPM2_SignHashScheme(dev, key, digest, digestSz, sig, sigSz,
sigAlg, WOLFTPM2_WRAP_DIGEST);
}
/* 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_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)
{
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) {
/* get curve size */
curveSize = wolfTPM2_GetCurveSize(
key->pub.publicArea.parameters.eccDetail.curveID);
if (curveSize <= 0 || sigSz < (curveSize * 2)) {
return BAD_FUNC_ARG;
}
/* verify curvesize 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 (sigSz > (int)sizeof(verifySigIn.signature.signature.rsassa.sig.buffer))
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 */
dev->session[0].auth = key->handle.auth;
dev->session[0].symmetric =
key->pub.publicArea.parameters.eccDetail.symmetric;
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);
}
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
return rc;
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_VerifySignature: Tag %d\n", verifySigOut.validation.tag);
#endif
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
return rc;
}
int wolfTPM2_VerifyHash_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
const byte* sig, int sigSz, const byte* digest, int digestSz,
int hashAlg)
{
TPM_ALG_ID sigAlg = TPM_ALG_NULL;
if (dev == NULL || key == NULL || digest == NULL || sig == NULL) {
return BAD_FUNC_ARG;
}
if (key->pub.publicArea.type == TPM_ALG_ECC) {
sigAlg = key->pub.publicArea.parameters.eccDetail.scheme.scheme;
}
else if (key->pub.publicArea.type == TPM_ALG_RSA) {
sigAlg = key->pub.publicArea.parameters.rsaDetail.scheme.scheme;
}
return wolfTPM2_VerifyHashScheme(dev, key, sig, sigSz, digest, digestSz,
sigAlg, hashAlg);
}
int wolfTPM2_VerifyHash(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
const byte* sig, int sigSz, const byte* digest, int digestSz)
{
return wolfTPM2_VerifyHash_ex(dev, key, sig, sigSz, digest, digestSz,
WOLFTPM2_WRAP_DIGEST);
}
/* 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 */
dev->session[0].auth = privKey->handle.auth;
dev->session[0].symmetric =
privKey->pub.publicArea.parameters.eccDetail.symmetric;
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
return rc;
}
*pubPoint = ecdhOut.pubPoint;
*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
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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 */
dev->session[0].auth = privKey->handle.auth;
dev->session[0].symmetric =
privKey->pub.publicArea.parameters.eccDetail.symmetric;
XMEMSET(&ecdhZIn, 0, sizeof(ecdhZIn));
ecdhZIn.keyHandle = privKey->handle.hndl;
ecdhZIn.inPoint = *pubPoint;
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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 */
ecdhKey->pub.publicArea.unique.ecc = out.Q.point;
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 */
dev->session[0].auth = parentKey->handle.auth;
dev->session[0].symmetric =
parentKey->pub.publicArea.parameters.eccDetail.symmetric;
XMEMSET(&inZGen2Ph, 0, sizeof(inZGen2Ph));
inZGen2Ph.keyA = ecdhKey->handle.hndl;
ecdhKey->handle.hndl = TPM_RH_NULL;
inZGen2Ph.inQsB = *pubPoint;
inZGen2Ph.inQeB = *pubPoint;
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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 */
dev->session[0].auth = key->handle.auth;
dev->session[0].symmetric =
key->pub.publicArea.parameters.rsaDetail.symmetric;
/* 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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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 for key */
dev->session[0].auth = key->handle.auth;
dev->session[0].symmetric =
key->pub.publicArea.parameters.rsaDetail.symmetric;
/* 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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
return rc;
}
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;
if (dev == NULL)
return BAD_FUNC_ARG;
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;
}
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;
NV_DefineSpace_In in;
if (dev == NULL || nv == NULL)
return BAD_FUNC_ARG;
/* set session auth for key */
dev->session[0].auth = parent->auth;
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 = TPM_ALG_SHA256;
in.publicInfo.nvPublic.attributes = nvAttributes;
in.publicInfo.nvPublic.dataSize = (UINT16)maxSize;
rc = TPM2_NV_DefineSpace(&in);
if (rc == TPM_RC_NV_DEFINED) {
#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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
return rc;
}
/* return new NV handle */
nv->handle.hndl = (TPM_HANDLE)nvIndex;
nv->handle.auth = in.auth;
#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
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
return 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;
/* set auth */
dev->session[0].auth = nv->handle.auth;
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
return rc;
}
#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;
}
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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 = 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;
dataSz = *pDataSz;
/* set auth */
dev->session[0].auth = nv->handle.auth;
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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;
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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 = authHandle;
return wolfTPM2_NVReadAuth(dev, &nv, nvIndex, dataBuf, pDataSz, offset);
}
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) {
XMEMCPY(nvPublic, &out.nvPublic.nvPublic, sizeof(*nvPublic));
}
return rc;
}
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 auth */
dev->session[0].auth = parent->auth;
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
return rc;
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_NV_UndefineSpace: Auth 0x%x, Idx 0x%x\n",
(word32)in.authHandle, (word32)in.nvIndex);
#endif
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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)
{
#ifdef WOLFTPM2_USE_WOLF_RNG
if (dev) {
return &dev->ctx.rng;
}
#endif
return NULL;
}
#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) {
/* caclulate 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) {
return BAD_FUNC_ARG;
}
/* Capture usage auth */
if (usageAuthSz > sizeof(hash->handle.auth.buffer))
usageAuthSz = sizeof(hash->handle.auth.buffer);
hash->handle.auth.size = usageAuthSz;
XMEMCPY(hash->handle.auth.buffer, usageAuth, usageAuthSz);
XMEMSET(&in, 0, sizeof(in));
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 */
dev->session[0].auth = hash->handle.auth;
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
return rc;
}
pos += hashSz;
}
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_HashUpdate: Handle 0x%x, DataSz %d\n",
(word32)in.sequenceHandle, dataSz);
#endif
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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 */
dev->session[0].auth = hash->handle.auth;
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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;
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 */
dev->session[0].auth = key->handle.auth;
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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);
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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 */
dev->session[0].auth = parent->auth;
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) {
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
return rc;
}
#ifdef DEBUG_WOLFTPM
printf("TPM2_Create key: pub %d, priv %d\n", createOut.outPublic.size,
createOut.outPrivate.size);
#endif
key->pub = createOut.outPublic;
/* Load new key */
XMEMSET(&loadIn, 0, sizeof(loadIn));
loadIn.parentHandle = parent->hndl;
loadIn.inPrivate = createOut.outPrivate;
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
return rc;
}
key->handle.hndl = loadOut.objectHandle;
key->handle.auth = createIn.inSensitive.sensitive.userAuth;
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_LoadKeyedHashKey Key Handle 0x%x\n",
(word32)key->handle.hndl);
#endif
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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 */
dev->session[0].auth = hmac->hash.handle.auth;
/* Setup HMAC start command */
XMEMSET(&in, 0, sizeof(in));
in.handle = hmac->key.handle.hndl;
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
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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
/* clear auth */
XMEMSET(&dev->session[0].auth, 0, sizeof(dev->session[0].auth));
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));
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);
}
/******************************************************************************/
/* --- END Wrapper Device Functions-- */
/******************************************************************************/
/******************************************************************************/
/* --- BEGIN Utility Functions -- */
/******************************************************************************/
static int GetKeyTemplateRSA(TPMT_PUBLIC* publicTemplate,
TPM_ALG_ID nameAlg, TPMA_OBJECT objectAttributes, int keyBits, int 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 = exponent;
publicTemplate->parameters.rsaDetail.scheme.scheme = sigScheme;
publicTemplate->parameters.rsaDetail.scheme.details.anySig.hashAlg = sigHash;
if (objectAttributes & TPMA_OBJECT_fixedTPM) {
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;
}
static 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;
XMEMSET(publicTemplate, 0, sizeof(TPMT_PUBLIC));
publicTemplate->type = TPM_ALG_ECC;
publicTemplate->nameAlg = nameAlg;
publicTemplate->unique.ecc.x.size = curveSz / 8;
publicTemplate->unique.ecc.y.size = curveSz / 8;
publicTemplate->objectAttributes = objectAttributes;
if (objectAttributes & TPMA_OBJECT_fixedTPM) {
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(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(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;
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_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;
}
int wolfTPM2_GetNvAttributesTemplate(TPM_HANDLE auth, word32* nvAttributes)
{
if (nvAttributes == NULL)
return BAD_FUNC_ARG;
*nvAttributes = (
TPMA_NV_AUTHWRITE | TPMA_NV_OWNERWRITE | /* write allowed */
TPMA_NV_AUTHREAD | TPMA_NV_OWNERREAD | /* read allowed */
TPMA_NV_NO_DA /* no dictionary attack */
);
if (auth == TPM_RH_PLATFORM) {
*nvAttributes |= (
TPMA_NV_PPWRITE | TPMA_NV_PPREAD
);
}
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_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;
/* TPM_RH_NULL is a valid handle for NULL signature */
getTimeCmd.signHandle = aikKey->handle.hndl;
/* TPM_ALG_NULL is a valid handle for NULL signature */
getTimeCmd.inScheme.scheme = TPM_ALG_RSASSA;
getTimeCmd.inScheme.details.rsassa.hashAlg = TPM_ALG_SHA256;
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;
}
/******************************************************************************/
/* --- END Utility Functions -- */
/******************************************************************************/
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && (defined(WOLF_CRYPTO_DEV) || defined(WOLF_CRYPTO_CB))
/******************************************************************************/
/* --- BEGIN wolf Crypto Device Support -- */
/******************************************************************************/
/* Internal structure for tracking hash state */
typedef struct WOLFTPM2_HASHCTX {
TPM_HANDLE handle;
#ifdef WOLFTPM_USE_SYMMETRIC
byte* cacheBuf; /* buffer */
word32 cacheBufSz; /* buffer size */
word32 cacheSz; /* filled size */
#endif
} WOLFTPM2_HASHCTX;
#ifdef WOLFTPM_USE_SYMMETRIC
#ifndef WOLFTPM2_HASH_BLOCK_SZ
#define WOLFTPM2_HASH_BLOCK_SZ 256
#endif
static int wolfTPM2_HashUpdateCache(WOLFTPM2_HASHCTX* hashCtx,
const byte* in, word32 inSz)
{
int ret = 0;
/* allocate new cache buffer */
if (hashCtx->cacheBuf == NULL) {
hashCtx->cacheSz = 0;
hashCtx->cacheBufSz = (inSz + WOLFTPM2_HASH_BLOCK_SZ - 1)
& ~(WOLFTPM2_HASH_BLOCK_SZ - 1);
if (hashCtx->cacheBufSz == 0)
hashCtx->cacheBufSz = WOLFTPM2_HASH_BLOCK_SZ;
hashCtx->cacheBuf = (byte*)XMALLOC(hashCtx->cacheBufSz,
NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (hashCtx->cacheBuf == NULL) {
return MEMORY_E;
}
}
/* determine if we need to grow buffer */
else if ((hashCtx->cacheSz + inSz) > hashCtx->cacheBufSz) {
byte* oldIn = hashCtx->cacheBuf;
hashCtx->cacheBufSz = (hashCtx->cacheSz + inSz +
WOLFTPM2_HASH_BLOCK_SZ - 1) & ~(WOLFTPM2_HASH_BLOCK_SZ - 1);
hashCtx->cacheBuf = (byte*)XMALLOC(hashCtx->cacheBufSz,
NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (hashCtx->cacheBuf == NULL) {
return MEMORY_E;
}
XMEMCPY(hashCtx->cacheBuf, oldIn, hashCtx->cacheSz);
XFREE(oldIn, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
/* copy input to new buffer */
XMEMCPY(&hashCtx->cacheBuf[hashCtx->cacheSz], in, inSz);
hashCtx->cacheSz += inSz;
return ret;
}
#endif /* WOLFTPM_USE_SYMMETRIC */
int wolfTPM2_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx)
{
int rc = CRYPTOCB_UNAVAILABLE;
int exit_rc;
TpmCryptoDevCtx* tlsCtx = (TpmCryptoDevCtx*)ctx;
if (info == NULL || ctx == NULL || tlsCtx->dev == NULL)
return BAD_FUNC_ARG;
/* for FIPS mode default error is not allowed, otherwise try and fallback
to software crypto */
exit_rc = tlsCtx->useFIPSMode ? FIPS_NOT_ALLOWED_E : CRYPTOCB_UNAVAILABLE;
(void)devId;
if (info->algo_type == WC_ALGO_TYPE_RNG) {
#ifndef WC_NO_RNG
#ifdef DEBUG_WOLFTPM
printf("CryptoDevCb RNG: Sz %d\n", info->rng.sz);
#endif
rc = wolfTPM2_GetRandom(tlsCtx->dev, info->rng.out, info->rng.sz);
#endif /* !WC_NO_RNG */
}
#if !defined(NO_RSA) || defined(HAVE_ECC)
else if (info->algo_type == WC_ALGO_TYPE_PK) {
int isWolfKeyValid = 1;
#ifdef DEBUG_WOLFTPM
printf("CryptoDevCb Pk: Type %d\n", info->pk.type);
#endif
/* optional callback to check key to determine if TPM should be used */
if (tlsCtx->checkKeyCb) {
/* this is useful to check the provided key for dummy key
cases like TLS server */
if (tlsCtx->checkKeyCb(info, tlsCtx) != 0) {
isWolfKeyValid = 0;
#ifdef DEBUG_WOLFTPM
printf("CryptoDevCb: Detected dummy key\n");
#endif
}
}
#ifndef NO_RSA
/* RSA */
if (info->pk.type == WC_PK_TYPE_RSA_KEYGEN) {
/* TODO: */
#if 0
RsaKey* key;
int size;
long e;
WC_RNG* rng;
#endif
rc = exit_rc;
}
else if (info->pk.type == WC_PK_TYPE_RSA) {
switch (info->pk.rsa.type) {
case RSA_PUBLIC_ENCRYPT:
case RSA_PUBLIC_DECRYPT:
{
/* public operations */
WOLFTPM2_KEY rsaPub;
if (!isWolfKeyValid && tlsCtx->rsaKey) {
/* use already loaded TPM handle for operation */
rc = wolfTPM2_RsaEncrypt(tlsCtx->dev, tlsCtx->rsaKey,
TPM_ALG_NULL, /* no padding */
info->pk.rsa.in, info->pk.rsa.inLen,
info->pk.rsa.out, (int*)info->pk.rsa.outLen);
break;
}
/* otherwise load public key and perform public op */
/* load public key into TPM */
rc = wolfTPM2_RsaKey_WolfToTpm(tlsCtx->dev,
info->pk.rsa.key, &rsaPub);
if (rc != 0) {
/* A failure of TPM_RC_KEY can happen due to unsupported
RSA exponents. In those cases return NOT_COMPILED_IN
and use software */
rc = exit_rc;
break;
}
/* public operations */
rc = wolfTPM2_RsaEncrypt(tlsCtx->dev, &rsaPub,
TPM_ALG_NULL, /* no padding */
info->pk.rsa.in, info->pk.rsa.inLen,
info->pk.rsa.out, (int*)info->pk.rsa.outLen);
wolfTPM2_UnloadHandle(tlsCtx->dev, &rsaPub.handle);
break;
}
case RSA_PRIVATE_ENCRYPT:
case RSA_PRIVATE_DECRYPT:
{
/* private operations */
rc = wolfTPM2_RsaDecrypt(tlsCtx->dev, tlsCtx->rsaKey,
TPM_ALG_NULL, /* no padding */
info->pk.rsa.in, info->pk.rsa.inLen,
info->pk.rsa.out, (int*)info->pk.rsa.outLen);
break;
}
}
}
#endif /* !NO_RSA */
#ifdef HAVE_ECC
if (info->pk.type == WC_PK_TYPE_EC_KEYGEN) {
#ifdef WOLFTPM2_USE_SW_ECDHE
rc = exit_rc;
#else
int curve_id;
/* Make sure an ECDH key has been set and curve is supported */
rc = TPM2_GetTpmCurve(info->pk.eckg.curveId);
if (rc < 0 || tlsCtx->ecdhKey == NULL || tlsCtx->eccKey == NULL) {
return exit_rc;
}
curve_id = rc;
/* Generate ephemeral key */
rc = wolfTPM2_ECDHGenKey(tlsCtx->dev, tlsCtx->ecdhKey, curve_id,
(byte*)tlsCtx->eccKey->handle.auth.buffer,
tlsCtx->eccKey->handle.auth.size);
if (rc == 0) {
/* Export public key info to wolf ecc_key */
rc = wolfTPM2_EccKey_TpmToWolf(tlsCtx->dev, tlsCtx->ecdhKey,
info->pk.eckg.key);
if (rc != 0) {
/* if failure, release key */
wolfTPM2_UnloadHandle(tlsCtx->dev, &tlsCtx->ecdhKey->handle);
}
}
else if (rc & TPM_RC_CURVE) {
/* if the curve is not supported on TPM, then fall-back to software */
rc = exit_rc;
/* Make sure ECDHE key indicates nothing loaded */
tlsCtx->ecdhKey->handle.hndl = TPM_RH_NULL;
}
#endif /* WOLFTPM2_USE_SW_ECDHE */
}
else if (info->pk.type == WC_PK_TYPE_ECDSA_SIGN) {
byte sigRS[MAX_ECC_BYTES*2];
byte *r = sigRS, *s;
word32 rsLen = sizeof(sigRS), rLen, sLen;
word32 inlen = info->pk.eccsign.inlen;
/* truncate input to match key size */
rLen = wc_ecc_size(info->pk.eccsign.key);
if (inlen > rLen)
inlen = rLen;
rc = wolfTPM2_SignHash(tlsCtx->dev, tlsCtx->eccKey,
info->pk.eccsign.in, inlen, sigRS, (int*)&rsLen);
if (rc == 0) {
/* Encode ECDSA Header */
rLen = sLen = rsLen / 2;
s = &sigRS[rLen];
rc = wc_ecc_rs_raw_to_sig(r, rLen, s, sLen,
info->pk.eccsign.out, info->pk.eccsign.outlen);
}
}
else if (info->pk.type == WC_PK_TYPE_ECDSA_VERIFY) {
WOLFTPM2_KEY eccPub;
byte sigRS[MAX_ECC_BYTES*2];
byte *r = sigRS, *s = &sigRS[MAX_ECC_BYTES];
word32 rLen = MAX_ECC_BYTES, sLen = MAX_ECC_BYTES;
/* Decode ECDSA Header */
rc = wc_ecc_sig_to_rs(info->pk.eccverify.sig,
info->pk.eccverify.siglen, r, &rLen, s, &sLen);
if (rc == 0) {
/* load public key into TPM */
rc = wolfTPM2_EccKey_WolfToTpm(tlsCtx->dev,
info->pk.eccverify.key, &eccPub);
if (rc == 0) {
/* combine R and S */
XMEMCPY(sigRS + rLen, s, sLen);
rc = wolfTPM2_VerifyHash(tlsCtx->dev, &eccPub,
sigRS, rLen + sLen,
info->pk.eccverify.hash, info->pk.eccverify.hashlen);
if (rc == 0 && info->pk.eccverify.res) {
*info->pk.eccverify.res = 1;
}
wolfTPM2_UnloadHandle(tlsCtx->dev, &eccPub.handle);
}
else if (rc & TPM_RC_CURVE) {
/* if the curve is not supported on TPM, then fall-back to software */
rc = exit_rc;
}
}
}
else if (info->pk.type == WC_PK_TYPE_ECDH) {
#ifdef WOLFTPM2_USE_SW_ECDHE
rc = exit_rc;
#else
TPM2B_ECC_POINT pubPoint;
/* Make sure an ECDH key has been set */
if (tlsCtx->ecdhKey == NULL || tlsCtx->eccKey == NULL ||
tlsCtx->ecdhKey->handle.hndl == TPM_RH_NULL) {
return exit_rc;
}
rc = wolfTPM2_EccKey_WolfToPubPoint(tlsCtx->dev,
info->pk.ecdh.public_key, &pubPoint);
if (rc == 0) {
/* Compute shared secret and compare results */
rc = wolfTPM2_ECDHGenZ(tlsCtx->dev, tlsCtx->ecdhKey,
&pubPoint, info->pk.ecdh.out, (int*)info->pk.ecdh.outlen);
}
/* done with ephemeral key */
wolfTPM2_UnloadHandle(tlsCtx->dev, &tlsCtx->ecdhKey->handle);
#endif /* !WOLFTPM2_USE_SW_ECDHE */
}
#endif /* HAVE_ECC */
(void)isWolfKeyValid;
}
#endif /* !NO_RSA || HAVE_ECC */
#ifndef NO_AES
else if (info->algo_type == WC_ALGO_TYPE_CIPHER) {
#ifdef DEBUG_WOLFTPM
printf("CryptoDevCb Cipher: Type %d\n", info->cipher.type);
#endif
if (info->cipher.type != WC_CIPHER_AES_CBC) {
return exit_rc;
}
#ifdef WOLFTPM_USE_SYMMETRIC
if (info->cipher.aescbc.aes) {
WOLFTPM2_KEY symKey;
Aes* aes = info->cipher.aescbc.aes;
if (aes == NULL) {
return BAD_FUNC_ARG;
}
if (!tlsCtx->useSymmetricOnTPM) {
return exit_rc;
}
/* load key */
XMEMSET(&symKey, 0, sizeof(symKey));
rc = wolfTPM2_LoadSymmetricKey(tlsCtx->dev, &symKey,
TPM_ALG_CBC, (byte*)aes->devKey, aes->keylen);
if (rc == 0) {
/* perform symmetric encrypt/decrypt */
rc = wolfTPM2_EncryptDecrypt(tlsCtx->dev, &symKey,
info->cipher.aescbc.in,
info->cipher.aescbc.out,
info->cipher.aescbc.sz,
(byte*)aes->reg, MAX_AES_BLOCK_SIZE_BYTES,
info->cipher.enc ? WOLFTPM2_ENCRYPT : WOLFTPM2_DECRYPT);
/* done with handle */
wolfTPM2_UnloadHandle(tlsCtx->dev, &symKey.handle);
}
}
#endif /* WOLFTPM_USE_SYMMETRIC */
}
#endif /* !NO_AES */
#if !defined(NO_SHA) || !defined(NO_SHA256)
else if (info->algo_type == WC_ALGO_TYPE_HASH) {
#ifdef WOLFTPM_USE_SYMMETRIC
WOLFTPM2_HASH hash;
WOLFTPM2_HASHCTX* hashCtx = NULL;
TPM_ALG_ID hashAlg = TPM_ALG_ERROR;
word32 hashFlags = 0;
#endif
#ifdef DEBUG_WOLFTPM
printf("CryptoDevCb Hash: Type %d\n", info->hash.type);
#endif
if (info->hash.type != WC_HASH_TYPE_SHA &&
info->hash.type != WC_HASH_TYPE_SHA256) {
return exit_rc;
}
#ifdef WOLFTPM_USE_SYMMETRIC
if (!tlsCtx->useSymmetricOnTPM) {
return exit_rc;
}
#ifndef NO_SHA
if (info->hash.type == WC_HASH_TYPE_SHA) {
hashAlg = TPM_ALG_SHA1;
if (info->hash.sha1) {
hashCtx = (WOLFTPM2_HASHCTX*)info->hash.sha1->devCtx;
hashFlags = info->hash.sha1->flags;
}
}
#endif
#ifndef NO_SHA256
if (info->hash.type == WC_HASH_TYPE_SHA256) {
hashAlg = TPM_ALG_SHA256;
if (info->hash.sha256) {
hashCtx = (WOLFTPM2_HASHCTX*)info->hash.sha256->devCtx;
hashFlags = info->hash.sha256->flags;
}
}
#endif
if (hashAlg == TPM_ALG_ERROR) {
return exit_rc;
}
XMEMSET(&hash, 0, sizeof(hash));
if (hashCtx)
hash.handle.hndl = hashCtx->handle;
if (info->hash.in != NULL) { /* Update */
rc = 0;
/* If not single shot (update and final) then allocate context */
if (hashCtx == NULL && info->hash.digest == NULL) {
hashCtx = (WOLFTPM2_HASHCTX*)XMALLOC(sizeof(*hashCtx), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (hashCtx == NULL) {
return MEMORY_E;
}
XMEMSET(hashCtx, 0, sizeof(*hashCtx));
}
if (rc == 0) {
if (hashCtx && (hashFlags & WC_HASH_FLAG_WILLCOPY)) {
rc = wolfTPM2_HashUpdateCache(hashCtx,
info->hash.in, info->hash.inSz);
}
else {
if (hash.handle.hndl == 0) {
rc = wolfTPM2_HashStart(tlsCtx->dev, &hash, hashAlg,
NULL, 0);
if (rc == 0) {
/* save new handle to hash context */
if (hashCtx)
hashCtx->handle = hash.handle.hndl;
}
}
if (rc == 0) {
rc = wolfTPM2_HashUpdate(tlsCtx->dev, &hash,
info->hash.in, info->hash.inSz);
}
}
}
}
if (info->hash.digest != NULL) { /* Final */
word32 digestSz = TPM2_GetHashDigestSize(hashAlg);
if (hashCtx && (hashFlags & WC_HASH_FLAG_WILLCOPY)) {
if (hash.handle.hndl == 0) {
rc = wolfTPM2_HashStart(tlsCtx->dev, &hash, hashAlg,
NULL, 0);
if (rc == 0) {
/* save new handle to hash context */
if (hashCtx)
hashCtx->handle = hash.handle.hndl;
}
}
if (rc == 0) {
rc = wolfTPM2_HashUpdate(tlsCtx->dev, &hash,
hashCtx->cacheBuf, hashCtx->cacheSz);
}
}
if (rc == 0) {
rc = wolfTPM2_HashFinish(tlsCtx->dev, &hash, info->hash.digest,
&digestSz);
}
}
/* if final or failure cleanup */
if (info->hash.digest != NULL || rc != 0) {
if (hashCtx) {
hashCtx->handle = 0; /* clear hash handle */
if ((hashFlags & WC_HASH_FLAG_ISCOPY) == 0) {
if (hashCtx->cacheBuf) {
XFREE(hashCtx->cacheBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
hashCtx->cacheBuf = NULL;
}
XFREE(hashCtx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
hashCtx = NULL;
}
/* Make sure hash if free'd in case of failure */
wolfTPM2_UnloadHandle(tlsCtx->dev, &hash.handle);
}
/* save hashCtx to hash structure */
#ifndef NO_SHA
if (info->hash.type == WC_HASH_TYPE_SHA && info->hash.sha1)
info->hash.sha1->devCtx = hashCtx;
#endif
#ifndef NO_SHA256
if (info->hash.type == WC_HASH_TYPE_SHA256 && info->hash.sha256)
info->hash.sha256->devCtx = hashCtx;
#endif
#endif /* WOLFTPM_USE_SYMMETRIC */
}
#endif /* !NO_SHA || !NO_SHA256 */
#ifndef NO_HMAC
else if (info->algo_type == WC_ALGO_TYPE_HMAC) {
#ifdef WOLFTPM_USE_SYMMETRIC
WOLFTPM2_HMAC* hmacCtx;
TPM_ALG_ID hashAlg = TPM_ALG_ERROR;
#endif
#ifdef DEBUG_WOLFTPM
printf("CryptoDevCb HMAC: Type %d\n", info->hmac.macType);
#endif
if (info->hmac.macType != WC_HASH_TYPE_SHA &&
info->hmac.macType != WC_HASH_TYPE_SHA256) {
return exit_rc;
}
if (info->hmac.hmac == NULL) {
/* make sure HMAC context exists */
return exit_rc;
}
#ifdef WOLFTPM_USE_SYMMETRIC
if (!tlsCtx->useSymmetricOnTPM) {
return exit_rc;
}
#ifndef NO_SHA
if (info->hmac.macType == WC_HASH_TYPE_SHA) {
hashAlg = TPM_ALG_SHA1;
}
#endif
#ifndef NO_SHA256
if (info->hmac.macType == WC_HASH_TYPE_SHA256) {
hashAlg = TPM_ALG_SHA256;
}
#endif
if (hashAlg == TPM_ALG_ERROR) {
return exit_rc;
}
hmacCtx = (WOLFTPM2_HMAC*)info->hmac.hmac->devCtx;
if (hmacCtx && hmacCtx->hash.handle.hndl == 0) {
#ifdef DEBUG_WOLFTPM
printf("Error: HMAC context invalid!\n");
return BAD_FUNC_ARG;
#endif
}
if (info->hmac.in != NULL) { /* Update */
rc = 0;
if (hmacCtx == NULL) {
const byte* keyBuf = info->hmac.hmac->keyRaw;
word32 keySz = info->hmac.hmac->keyLen;
hmacCtx = (WOLFTPM2_HMAC*)XMALLOC(sizeof(*hmacCtx), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (hmacCtx == NULL) {
return MEMORY_E;
}
XMEMSET(hmacCtx, 0, sizeof(*hmacCtx));
rc = wolfTPM2_HmacStart(tlsCtx->dev, hmacCtx,
tlsCtx->storageKey ? &tlsCtx->storageKey->handle : NULL,
hashAlg, keyBuf, keySz, NULL, 0);
}
if (rc == 0) {
rc = wolfTPM2_HmacUpdate(tlsCtx->dev, hmacCtx,
info->hmac.in, info->hmac.inSz);
}
}
if (info->hmac.digest != NULL) { /* Final */
word32 digestSz = TPM2_GetHashDigestSize(hashAlg);
rc = wolfTPM2_HmacFinish(tlsCtx->dev, hmacCtx, info->hmac.digest,
&digestSz);
}
/* clean hmac context */
if (rc != 0 || info->hmac.digest != NULL) {
wolfTPM2_UnloadHandle(tlsCtx->dev, &hmacCtx->hash.handle);
wolfTPM2_UnloadHandle(tlsCtx->dev, &hmacCtx->key.handle);
XFREE(hmacCtx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
hmacCtx = NULL;
}
info->hmac.hmac->devCtx = hmacCtx;
#endif /* WOLFTPM_USE_SYMMETRIC */
}
#endif /* !NO_HMAC */
/* need to return negative here for error */
if (rc != TPM_RC_SUCCESS && rc != exit_rc) {
#ifdef DEBUG_WOLFTPM
printf("wolfTPM2_CryptoDevCb failed rc = %d\n", rc);
#endif
rc = WC_HW_E;
}
return rc;
}
int wolfTPM2_SetCryptoDevCb(WOLFTPM2_DEV* dev, CryptoDevCallbackFunc cb,
TpmCryptoDevCtx* tpmCtx, int* pDevId)
{
int rc;
int devId = INVALID_DEVID;
if (dev == NULL || cb == NULL || tpmCtx == NULL) {
return BAD_FUNC_ARG;
}
/* register a crypto device callback for TPM private key */
rc = wolfTPM2_GetTpmDevId(dev);
if (rc >= 0) {
devId = rc;
tpmCtx->dev = dev;
rc = wc_CryptoDev_RegisterDevice(devId, cb, tpmCtx);
}
if (pDevId) {
*pDevId = devId;
}
return rc;
}
int wolfTPM2_ClearCryptoDevCb(WOLFTPM2_DEV* dev, int devId)
{
int rc = 0;
if (dev == NULL) {
return BAD_FUNC_ARG;
}
/* get device Id */
if (devId == INVALID_DEVID) {
rc = wolfTPM2_GetTpmDevId(dev);
if (rc >= 0) {
devId = rc;
rc = 0;
}
}
if (devId != INVALID_DEVID) {
wc_CryptoCb_UnRegisterDevice(devId);
}
return rc;
}
/******************************************************************************/
/* --- END wolf Crypto Device Support -- */
/******************************************************************************/
#endif /* !WOLFTPM2_NO_WOLFCRYPT && (WOLF_CRYPTO_DEV || WOLF_CRYPTO_CB) */
#endif /* !WOLFTPM2_NO_WRAPPER */