Skip to content

Commit 23b3ed6

Browse files
authored
Merge pull request #488 from aidangarske/fenrir-fixes-8
Add Unit Testing, Fix Short Curcuits, Other fixes
2 parents f1afb9f + 2c02c7f commit 23b3ed6

17 files changed

Lines changed: 948 additions & 133 deletions

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ make install
203203

204204
```text
205205
--enable-debug Add debug code/turns off optimizations (yes|no|verbose|io) - DEBUG_WOLFTPM, WOLFTPM_DEBUG_VERBOSE, WOLFTPM_DEBUG_IO
206+
WARNING: Define WOLFTPM_DEBUG_SECRETS manually (NOT enabled by default and NOT
207+
exposed via configure) to additionally print sensitive material — auth values,
208+
session keys, bind keys, HMAC keys, hierarchy auth, and encryption secrets.
209+
For developer debugging only. NEVER enable in production builds or on devices
210+
that log stdout to persistent storage.
206211
--enable-examples Enable Examples (default: enabled)
207212
--enable-wrapper Enable wrapper code (default: enabled) - WOLFTPM2_NO_WRAPPER
208213
--enable-wolfcrypt Enable wolfCrypt hooks for RNG, Auth Sessions and Parameter encryption (default: enabled) - WOLFTPM2_NO_WOLFCRYPT

examples/bench/bench.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ static int bench_sym_aes(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* storageKey,
160160
double start;
161161
TPMT_PUBLIC publicTemplate;
162162
WOLFTPM2_KEY aesKey;
163+
byte iv[MAX_AES_BLOCK_SIZE_BYTES];
163164

164165
XMEMSET(&aesKey, 0, sizeof(aesKey));
165166
rc = wolfTPM2_GetKeyTemplate_Symmetric(&publicTemplate, keyBits, algo,
@@ -175,8 +176,9 @@ static int bench_sym_aes(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* storageKey,
175176

176177
bench_stats_start(&count, &start);
177178
do {
178-
rc = wolfTPM2_EncryptDecrypt(dev, &aesKey, in, out, inOutSz, NULL, 0,
179-
isDecrypt);
179+
XMEMSET(iv, 0, sizeof(iv));
180+
rc = wolfTPM2_EncryptDecrypt(dev, &aesKey, in, out, inOutSz, iv,
181+
sizeof(iv), isDecrypt);
180182
if (WOLFTPM_IS_COMMAND_UNAVAILABLE(rc)) {
181183
printf("Encrypt/Decrypt unavailable\n");
182184
break;

examples/pcr/policy_sign.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -192,14 +192,15 @@ static int PolicySign(TPM_ALG_ID alg, const char* keyFile, const char* password,
192192
rc = wc_ecc_sign_hash_ex(hash, hashSz, &rng, &key.ecc, &r, &s);
193193
}
194194
if (rc == 0) {
195-
word32 keySz = key.ecc.dp->size, rSz, sSz;
195+
word32 keySz = key.ecc.dp->size;
196196
*sigSz = keySz * 2;
197+
/* Pre-zero in case mp export fails and leaves the buffer
198+
* partially written. Fixed-width export of r and s
199+
* removes the data-dependent wire offset that previously
200+
* leaked the leading-zero count. */
197201
XMEMSET(sig, 0, *sigSz);
198-
/* export sign r/s - zero pad to key size */
199-
rSz = mp_unsigned_bin_size(&r);
200-
mp_to_unsigned_bin(&r, &sig[keySz - rSz]);
201-
sSz = mp_unsigned_bin_size(&s);
202-
mp_to_unsigned_bin(&s, &sig[keySz + (keySz - sSz)]);
202+
mp_to_unsigned_bin_len(&r, &sig[0], keySz);
203+
mp_to_unsigned_bin_len(&s, &sig[keySz], keySz);
203204
mp_clear(&r);
204205
mp_clear(&s);
205206
}

examples/wrap/wrap_test.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -960,14 +960,16 @@ int TPM2_Wrapper_TestArgs(void* userCtx, int argc, char *argv[])
960960

961961
XMEMSET(cipher.buffer, 0, sizeof(cipher.buffer));
962962
cipher.size = message.size;
963+
XMEMSET(aesIv, 0, sizeof(aesIv));
963964
rc = wolfTPM2_EncryptDecrypt(&dev, &aesKey, message.buffer, cipher.buffer,
964-
message.size, NULL, 0, WOLFTPM2_ENCRYPT);
965+
message.size, aesIv, (word32)sizeof(aesIv), WOLFTPM2_ENCRYPT);
965966
if (rc != 0 && !WOLFTPM_IS_COMMAND_UNAVAILABLE(rc)) goto exit;
966967

967968
XMEMSET(plain.buffer, 0, sizeof(plain.buffer));
968969
plain.size = message.size;
970+
XMEMSET(aesIv, 0, sizeof(aesIv));
969971
rc = wolfTPM2_EncryptDecrypt(&dev, &aesKey, cipher.buffer, plain.buffer,
970-
cipher.size, NULL, 0, WOLFTPM2_DECRYPT);
972+
cipher.size, aesIv, (word32)sizeof(aesIv), WOLFTPM2_DECRYPT);
971973

972974
wolfTPM2_UnloadHandle(&dev, &aesKey.handle);
973975

hal/tpm_io_zephyr.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,9 @@ int TPM2_IoCb_Zephyr_I2C(TPM2_CTX* ctx, int isRead, word32 addr,
169169
}
170170

171171
#else /* If not I2C, it must be SPI */
172-
/* TODO implement SPI */
173-
#error TPM2 SPI support on zephyr yet
172+
#error "TPM2 SPI transport is not implemented on Zephyr. \
173+
Define WOLFTPM_I2C to use the I2C transport, or supply your own SPI \
174+
TPM2_IoCb callback via wolfTPM2_Init()."
174175
#endif
175176

176177
#endif /* WOLFSSL_ZEPHYR */

src/fwtpm/fwtpm_command.c

Lines changed: 120 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -8228,6 +8228,10 @@ static TPM_RC FwCmd_PolicyAuthorize(FWTPM_CTX* ctx, TPM2_Packet* cmd,
82288228
int expectedSz = 0;
82298229
wc_HashAlg aCtx;
82308230
enum wc_HashType aWcHash;
8231+
int hmacRc;
8232+
int sizeMismatch;
8233+
int ticketDiff;
8234+
word32 cmpSz;
82318235

82328236
/* Step 1: aHash = H(approvedPolicy || policyRef)
82338237
* Hash algorithm comes from signing key's nameAlg */
@@ -8254,20 +8258,24 @@ static TPM_RC FwCmd_PolicyAuthorize(FWTPM_CTX* ctx, TPM2_Packet* cmd,
82548258
ticketInputSz += keySignNameSz;
82558259
}
82568260

8257-
/* Step 3: verify ticket HMAC */
8258-
if (rc == 0 &&
8259-
(FwComputeTicketHmac(ctx, ticketHier, keyNameAlg,
8260-
ticketInput, ticketInputSz,
8261-
expectedHmac, &expectedSz) != 0 ||
8262-
ticketDigestSz != (UINT16)expectedSz ||
8263-
TPM2_ConstantCompare(ticketDigest, expectedHmac,
8264-
(word32)expectedSz) != 0)) {
8265-
#ifdef DEBUG_WOLFTPM
8266-
printf("fwTPM: PolicyAuthorize ticket verify failed "
8267-
"(tag=0x%x, hier=0x%x, ticketSz=%d, expectedSz=%d)\n",
8268-
ticketTag, ticketHier, ticketDigestSz, expectedSz);
8269-
#endif
8270-
rc = TPM_RC_POLICY_FAIL;
8261+
/* Step 3: verify ticket HMAC — always run TPM2_ConstantCompare
8262+
* so timing doesn't leak size match */
8263+
if (rc == 0) {
8264+
hmacRc = FwComputeTicketHmac(ctx, ticketHier, keyNameAlg,
8265+
ticketInput, ticketInputSz, expectedHmac, &expectedSz);
8266+
sizeMismatch = (ticketDigestSz != (UINT16)expectedSz);
8267+
cmpSz = (ticketDigestSz < (UINT16)expectedSz) ?
8268+
ticketDigestSz : (word32)expectedSz;
8269+
ticketDiff = TPM2_ConstantCompare(ticketDigest, expectedHmac,
8270+
cmpSz);
8271+
if (hmacRc != 0 || (sizeMismatch | ticketDiff)) {
8272+
#ifdef DEBUG_WOLFTPM
8273+
printf("fwTPM: PolicyAuthorize ticket verify failed "
8274+
"(tag=0x%x, hier=0x%x, ticketSz=%d, expectedSz=%d)\n",
8275+
ticketTag, ticketHier, ticketDigestSz, expectedSz);
8276+
#endif
8277+
rc = TPM_RC_POLICY_FAIL;
8278+
}
82718279
}
82728280
TPM2_ForceZero(aHash, sizeof(aHash));
82738281
TPM2_ForceZero(expectedHmac, sizeof(expectedHmac));
@@ -9005,6 +9013,9 @@ static TPM_RC FwCmd_PolicyCpHash(FWTPM_CTX* ctx, TPM2_Packet* cmd,
90059013
FWTPM_Session* sess;
90069014
UINT16 cpHashSz = 0;
90079015
byte cpHashBuf[TPM_MAX_DIGEST_SIZE];
9016+
int sizeMismatch;
9017+
int cpDiff;
9018+
word32 cmpSz;
90089019
(void)cmdSize;
90099020

90109021
sess = FwPolicyParseSession(ctx, cmd, cmdSize, cmdTag);
@@ -9025,11 +9036,15 @@ static TPM_RC FwCmd_PolicyCpHash(FWTPM_CTX* ctx, TPM2_Packet* cmd,
90259036
if (rc == 0) {
90269037
TPM2_Packet_ParseBytes(cmd, cpHashBuf, cpHashSz);
90279038

9028-
/* If cpHashA already set, must be identical */
9039+
/* If cpHashA already set, must be identical — always run
9040+
* TPM2_ConstantCompare so timing doesn't leak size match */
90299041
if (sess->cpHashA.size > 0) {
9030-
if (sess->cpHashA.size != cpHashSz ||
9031-
TPM2_ConstantCompare(sess->cpHashA.buffer, cpHashBuf,
9032-
cpHashSz) != 0) {
9042+
sizeMismatch = (sess->cpHashA.size != cpHashSz);
9043+
cmpSz = (sess->cpHashA.size < cpHashSz) ?
9044+
sess->cpHashA.size : cpHashSz;
9045+
cpDiff = TPM2_ConstantCompare(sess->cpHashA.buffer, cpHashBuf,
9046+
cmpSz);
9047+
if (sizeMismatch | cpDiff) {
90339048
rc = TPM_RC_CPHASH;
90349049
}
90359050
}
@@ -9064,6 +9079,9 @@ static TPM_RC FwCmd_PolicyNameHash(FWTPM_CTX* ctx, TPM2_Packet* cmd,
90649079
FWTPM_Session* sess;
90659080
UINT16 nameHashSz = 0;
90669081
byte nameHashBuf[TPM_MAX_DIGEST_SIZE];
9082+
int sizeMismatch;
9083+
int nameDiff;
9084+
word32 cmpSz;
90679085
(void)cmdSize;
90689086

90699087
sess = FwPolicyParseSession(ctx, cmd, cmdSize, cmdTag);
@@ -9084,11 +9102,15 @@ static TPM_RC FwCmd_PolicyNameHash(FWTPM_CTX* ctx, TPM2_Packet* cmd,
90849102
if (rc == 0) {
90859103
TPM2_Packet_ParseBytes(cmd, nameHashBuf, nameHashSz);
90869104

9087-
/* If nameHash already set, must be identical */
9105+
/* If nameHash already set, must be identical — always run
9106+
* TPM2_ConstantCompare so timing doesn't leak size match */
90889107
if (sess->nameHash.size > 0) {
9089-
if (sess->nameHash.size != nameHashSz ||
9090-
TPM2_ConstantCompare(sess->nameHash.buffer, nameHashBuf,
9091-
nameHashSz) != 0) {
9108+
sizeMismatch = (sess->nameHash.size != nameHashSz);
9109+
cmpSz = (sess->nameHash.size < nameHashSz) ?
9110+
sess->nameHash.size : nameHashSz;
9111+
nameDiff = TPM2_ConstantCompare(sess->nameHash.buffer, nameHashBuf,
9112+
cmpSz);
9113+
if (sizeMismatch | nameDiff) {
90929114
rc = TPM_RC_CPHASH;
90939115
}
90949116
}
@@ -9436,6 +9458,9 @@ static TPM_RC FwCmd_PolicyTicket(FWTPM_CTX* ctx, TPM2_Packet* cmd,
94369458
FWTPM_Session* sess;
94379459
INT32 expiration = 0;
94389460
UINT32 extendCC;
9461+
int cpaSizeMismatch;
9462+
int cpaDiff;
9463+
word32 cpaCmpSz;
94399464
(void)cmdSize;
94409465

94419466
TPM2_Packet_ParseU32(cmd, &sessHandle);
@@ -9522,6 +9547,10 @@ static TPM_RC FwCmd_PolicyTicket(FWTPM_CTX* ctx, TPM2_Packet* cmd,
95229547
enum wc_HashType aWcHash;
95239548
int aHashSz;
95249549
byte expBuf[4];
9550+
int hmacRc;
9551+
int sizeMismatch;
9552+
int ticketDiff;
9553+
word32 cmpSz;
95259554

95269555
aWcHash = FwGetWcHashType(sess->authHash);
95279556
aHashSz = TPM2_GetHashDigestSize(sess->authHash);
@@ -9551,15 +9580,19 @@ static TPM_RC FwCmd_PolicyTicket(FWTPM_CTX* ctx, TPM2_Packet* cmd,
95519580
ticketInputSz += authNameSz;
95529581
}
95539582

9554-
/* Verify HMAC */
9555-
if (rc == 0 &&
9556-
(FwComputeTicketHmac(ctx, ticketHier, sess->authHash,
9557-
ticketInput, ticketInputSz,
9558-
expectedHmac, &expectedSz) != 0 ||
9559-
ticketDigestSz != (UINT16)expectedSz ||
9560-
TPM2_ConstantCompare(ticketDigest, expectedHmac,
9561-
(word32)expectedSz) != 0)) {
9562-
rc = TPM_RC_POLICY_FAIL;
9583+
/* Verify HMAC — always run TPM2_ConstantCompare so timing doesn't
9584+
* leak whether size matched */
9585+
if (rc == 0) {
9586+
hmacRc = FwComputeTicketHmac(ctx, ticketHier, sess->authHash,
9587+
ticketInput, ticketInputSz, expectedHmac, &expectedSz);
9588+
sizeMismatch = (ticketDigestSz != (UINT16)expectedSz);
9589+
cmpSz = (ticketDigestSz < (UINT16)expectedSz) ?
9590+
ticketDigestSz : (word32)expectedSz;
9591+
ticketDiff = TPM2_ConstantCompare(ticketDigest, expectedHmac,
9592+
cmpSz);
9593+
if (hmacRc != 0 || (sizeMismatch | ticketDiff)) {
9594+
rc = TPM_RC_POLICY_FAIL;
9595+
}
95639596
}
95649597
TPM2_ForceZero(aHash, sizeof(aHash));
95659598
TPM2_ForceZero(expectedHmac, sizeof(expectedHmac));
@@ -9582,13 +9615,18 @@ static TPM_RC FwCmd_PolicyTicket(FWTPM_CTX* ctx, TPM2_Packet* cmd,
95829615
}
95839616
}
95849617

9585-
/* Store cpHashA constraint if provided */
9618+
/* Store cpHashA constraint if provided — always run TPM2_ConstantCompare
9619+
* so timing doesn't leak size match */
95869620
if (rc == 0 && cpHashASz > 0) {
9587-
if (sess->cpHashA.size > 0 &&
9588-
(sess->cpHashA.size != cpHashASz ||
9589-
TPM2_ConstantCompare(sess->cpHashA.buffer, cpHashABuf,
9590-
cpHashASz) != 0)) {
9591-
rc = TPM_RC_CPHASH;
9621+
if (sess->cpHashA.size > 0) {
9622+
cpaSizeMismatch = (sess->cpHashA.size != cpHashASz);
9623+
cpaCmpSz = (sess->cpHashA.size < cpHashASz) ?
9624+
sess->cpHashA.size : cpHashASz;
9625+
cpaDiff = TPM2_ConstantCompare(sess->cpHashA.buffer, cpHashABuf,
9626+
cpaCmpSz);
9627+
if (cpaSizeMismatch | cpaDiff) {
9628+
rc = TPM_RC_CPHASH;
9629+
}
95929630
}
95939631
if (rc == 0) {
95949632
sess->cpHashA.size = cpHashASz;
@@ -9622,6 +9660,10 @@ static TPM_RC FwCmd_PolicyAuthorizeNV(FWTPM_CTX* ctx, TPM2_Packet* cmd,
96229660
byte ccBuf[4];
96239661
UINT32 cc = TPM_CC_PolicyAuthorizeNV;
96249662
int hashInit = 0;
9663+
int nvSizeMismatch;
9664+
int sessSizeMismatch;
9665+
int policyDiff;
9666+
word32 policyCmpSz;
96259667

96269668
(void)cmdSize;
96279669

@@ -9657,12 +9699,19 @@ static TPM_RC FwCmd_PolicyAuthorizeNV(FWTPM_CTX* ctx, TPM2_Packet* cmd,
96579699
rc = TPM_RC_HASH;
96589700
}
96599701

9660-
/* For policy sessions (not trial): verify policyDigest == NV data */
9702+
/* For policy sessions (not trial): verify policyDigest == NV data.
9703+
* Always run TPM2_ConstantCompare over min(sizes) so timing doesn't
9704+
* leak size match. */
96619705
if (rc == 0 && sess->sessionType == TPM_SE_POLICY) {
9662-
if ((int)nv->nvPublic.dataSize != dSz ||
9663-
(int)sess->policyDigest.size != dSz ||
9664-
TPM2_ConstantCompare(sess->policyDigest.buffer,
9665-
nv->data, (word32)dSz) != 0) {
9706+
nvSizeMismatch = ((int)nv->nvPublic.dataSize != dSz);
9707+
sessSizeMismatch = ((int)sess->policyDigest.size != dSz);
9708+
policyCmpSz = (sess->policyDigest.size < nv->nvPublic.dataSize) ?
9709+
sess->policyDigest.size : nv->nvPublic.dataSize;
9710+
if (policyCmpSz > (word32)dSz)
9711+
policyCmpSz = (word32)dSz;
9712+
policyDiff = TPM2_ConstantCompare(sess->policyDigest.buffer,
9713+
nv->data, policyCmpSz);
9714+
if (nvSizeMismatch | sessSizeMismatch | policyDiff) {
96669715
rc = TPM_RC_POLICY_FAIL;
96679716
}
96689717
}
@@ -12902,6 +12951,9 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
1290212951
FWTPM_Session* pSess = cmdAuths[pj].sess;
1290312952
TPM_HANDLE entityH = cmdHandles[pj];
1290412953
TPM2B_DIGEST* authPolicy = NULL;
12954+
int sizeMismatch;
12955+
int policyDiff;
12956+
word32 cmpSz;
1290512957

1290612958
/* Find entity's authPolicy by handle type */
1290712959
#ifndef FWTPM_NO_NV
@@ -12943,9 +12995,13 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
1294312995

1294412996
/* If entity has a non-empty authPolicy, it must match */
1294512997
if (authPolicy != NULL && authPolicy->size > 0) {
12946-
if (pSess->policyDigest.size != authPolicy->size ||
12947-
TPM2_ConstantCompare(pSess->policyDigest.buffer,
12948-
authPolicy->buffer, authPolicy->size) != 0) {
12998+
/* Always run TPM2_ConstantCompare so timing doesn't leak size */
12999+
sizeMismatch = (pSess->policyDigest.size != authPolicy->size);
13000+
cmpSz = (pSess->policyDigest.size < authPolicy->size) ?
13001+
pSess->policyDigest.size : authPolicy->size;
13002+
policyDiff = TPM2_ConstantCompare(pSess->policyDigest.buffer,
13003+
authPolicy->buffer, cmpSz);
13004+
if (sizeMismatch | policyDiff) {
1294913005
#ifdef DEBUG_WOLFTPM
1295013006
printf("fwTPM: Policy digest mismatch for handle "
1295113007
"0x%x (CC=0x%x)\n", entityH, cmdCode);
@@ -13072,6 +13128,9 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
1307213128
const byte* authVal = NULL;
1307313129
int authValSz = 0;
1307413130
TPM_HANDLE entityH;
13131+
int sizeMismatch;
13132+
int hmacDiff;
13133+
word32 cmpSz;
1307513134

1307613135
/* Compute cpHash = H(commandCode || handleNames || cpBuffer) */
1307713136
if (FwComputeCpHash(hSess->authHash, cmdCode,
@@ -13087,13 +13146,18 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
1308713146
FwLookupEntityAuth(ctx, entityH, &authVal, &authValSz);
1308813147

1308913148
/* PolicyPassword with no sessionKey (unsalted/unbound):
13090-
* HMAC field contains plaintext authValue per spec Section 19.6.13 */
13149+
* HMAC field contains plaintext authValue per spec Section 19.6.13.
13150+
* Always run TPM2_ConstantCompare so timing doesn't leak auth
13151+
* length match. */
1309113152
if (hSess->sessionType == TPM_SE_POLICY &&
1309213153
hSess->isPasswordPolicy &&
1309313154
hSess->sessionKey.size == 0) {
13094-
if ((int)cmdAuths[hj].cmdHmacSize != authValSz ||
13095-
TPM2_ConstantCompare(cmdAuths[hj].cmdHmac,
13096-
authVal, (word32)authValSz) != 0) {
13155+
sizeMismatch = ((int)cmdAuths[hj].cmdHmacSize != authValSz);
13156+
cmpSz = (cmdAuths[hj].cmdHmacSize < (UINT16)authValSz) ?
13157+
cmdAuths[hj].cmdHmacSize : (word32)authValSz;
13158+
hmacDiff = TPM2_ConstantCompare(cmdAuths[hj].cmdHmac,
13159+
authVal, cmpSz);
13160+
if (sizeMismatch | hmacDiff) {
1309713161
#ifdef DEBUG_WOLFTPM
1309813162
printf("fwTPM: PolicyPassword auth failed for handle "
1309913163
"0x%x (CC=0x%x)\n", entityH, cmdCode);
@@ -13120,9 +13184,13 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
1312013184
0, /* isResponse=0 for command HMAC */
1312113185
expectedHmac, &expectedSz);
1312213186

13123-
if (cmdAuths[hj].cmdHmacSize != (UINT16)expectedSz ||
13124-
TPM2_ConstantCompare(cmdAuths[hj].cmdHmac,
13125-
expectedHmac, (word32)expectedSz) != 0) {
13187+
/* Always run TPM2_ConstantCompare so timing doesn't leak size */
13188+
sizeMismatch = (cmdAuths[hj].cmdHmacSize != (UINT16)expectedSz);
13189+
cmpSz = (cmdAuths[hj].cmdHmacSize < (UINT16)expectedSz) ?
13190+
cmdAuths[hj].cmdHmacSize : (word32)expectedSz;
13191+
hmacDiff = TPM2_ConstantCompare(cmdAuths[hj].cmdHmac,
13192+
expectedHmac, cmpSz);
13193+
if (sizeMismatch | hmacDiff) {
1312613194
#ifdef DEBUG_WOLFTPM
1312713195
printf("fwTPM: HMAC session auth failed for handle "
1312813196
"0x%x (CC=0x%x)\n", entityH, cmdCode);

0 commit comments

Comments
 (0)