Skip to content

Commit 882b46f

Browse files
committed
F-3015 - https://fenrir.wolfssl.com/finding/3015 - Remove short-circuit OR in FwVerifySignatureCore RSA-PKCS1v1.5 check
1 parent 054a2d8 commit 882b46f

5 files changed

Lines changed: 53 additions & 16 deletions

File tree

examples/pcr/policy_sign.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,10 +194,16 @@ static int PolicySign(TPM_ALG_ID alg, const char* keyFile, const char* password,
194194
if (rc == 0) {
195195
word32 keySz = key.ecc.dp->size;
196196
*sigSz = keySz * 2;
197-
/* constant-time fixed-width export of r and s avoids
198-
* leaking the leading-zero count of each component */
197+
/* fixed-width export of r and s avoids leaking the
198+
* leading-zero count of each component via data-dependent
199+
* offsets */
200+
#ifdef WOLFSSL_HAVE_SP_ECC
199201
mp_to_unsigned_bin_len_ct(&r, &sig[0], keySz);
200202
mp_to_unsigned_bin_len_ct(&s, &sig[keySz], keySz);
203+
#else
204+
mp_to_unsigned_bin_len(&r, &sig[0], keySz);
205+
mp_to_unsigned_bin_len(&s, &sig[keySz], keySz);
206+
#endif
201207
mp_clear(&r);
202208
mp_clear(&s);
203209
}

src/fwtpm/fwtpm_crypto.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1835,9 +1835,12 @@ TPM_RC FwImportVerifyAndDecrypt(
18351835
}
18361836
}
18371837
if (rc == 0) {
1838-
/* Always run TPM2_ConstantCompare so timing doesn't leak size match */
1838+
/* Always run TPM2_ConstantCompare over min(sizes) so timing doesn't
1839+
* leak size match and we don't read past integrity[integritySize] */
1840+
word32 cmpSz = (integritySize < (UINT16)digestSz) ?
1841+
(word32)integritySize : (word32)digestSz;
18391842
sizeMismatch = (integritySize != (UINT16)digestSz);
1840-
hmacDiff = TPM2_ConstantCompare(integrity, hmacCalc, (word32)digestSz);
1843+
hmacDiff = TPM2_ConstantCompare(integrity, hmacCalc, cmpSz);
18411844
if (sizeMismatch | hmacDiff) {
18421845
rc = TPM_RC_INTEGRITY;
18431846
}
@@ -2543,18 +2546,29 @@ TPM_RC FwVerifySignatureCore(FWTPM_Object* obj,
25432546
(enum wc_HashType)wcHash);
25442547
int expSz = wc_EncodeSignature(expDI,
25452548
digest, digestSz, oid);
2549+
int sizeMismatch;
2550+
int sigDiff;
2551+
word32 cmpSz;
25462552

25472553
FWTPM_ALLOC_BUF(decSig, FWTPM_MAX_PUB_BUF);
25482554
wcRc = wc_RsaSSL_Verify(
25492555
sig->signature.rsassa.sig.buffer,
25502556
sig->signature.rsassa.sig.size,
25512557
decSig, (word32)FWTPM_MAX_PUB_BUF, rsaKey);
2552-
if (wcRc >= 0) {
2553-
if (wcRc != expSz || expSz <= 0 ||
2554-
TPM2_ConstantCompare(decSig, expDI, expSz) != 0) {
2558+
if (wcRc >= 0 && expSz > 0) {
2559+
/* Always run TPM2_ConstantCompare so timing doesn't
2560+
* leak decoded-length vs expected-length match */
2561+
sizeMismatch = (wcRc != expSz);
2562+
cmpSz = (wcRc < expSz) ? (word32)wcRc :
2563+
(word32)expSz;
2564+
sigDiff = TPM2_ConstantCompare(decSig, expDI, cmpSz);
2565+
if (sizeMismatch | sigDiff) {
25552566
wcRc = -1;
25562567
}
25572568
}
2569+
else if (wcRc >= 0) {
2570+
wcRc = -1;
2571+
}
25582572
FWTPM_FREE_BUF(decSig);
25592573
}
25602574
if (wcRc < 0)
@@ -2876,6 +2890,9 @@ TPM_RC FwCredentialUnwrap(
28762890
FWTPM_DECLARE_VAR(hmac, Hmac);
28772891
FWTPM_DECLARE_BUF(decBuf, FWTPM_MAX_NV_DATA + 2);
28782892

2893+
/* Zero-init so tail bytes are deterministic when integrityHmacSz < 32 */
2894+
TPM2_ForceZero(integrityHmac, sizeof(integrityHmac));
2895+
28792896
FWTPM_ALLOC_VAR(aes, Aes);
28802897
FWTPM_ALLOC_VAR(hmac, Hmac);
28812898
FWTPM_ALLOC_BUF(decBuf, FWTPM_MAX_NV_DATA + 2);

src/tpm2.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -386,9 +386,11 @@ static int TPM2_ResponseProcess(TPM2_CTX* ctx, TPM2_Packet* packet,
386386
return rc;
387387
}
388388

389-
/* Verify HMAC using constant-time comparison — always run
390-
* TPM2_ConstantCompare so code path timing doesn't depend on
391-
* whether the size matched. */
389+
/* Verify HMAC using constant-time comparison. The wire-format
390+
* size was already validated above; this branch-free pattern
391+
* hardens the tail check in case a future refactor removes
392+
* that gate (hmac.size and authRsp.hmac.size are both
393+
* algorithm-derived and non-secret at this point). */
392394
sizeMismatch = (hmac.size != authRsp.hmac.size);
393395
diff = TPM2_ConstantCompare(hmac.buffer, authRsp.hmac.buffer,
394396
expectedHmacSz);

src/tpm2_packet.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,11 @@ void TPM2_Packet_ParseSensitive(TPM2_Packet* packet, TPM2B_SENSITIVE* sensitive)
833833
if (sensitive->size == 0) {
834834
return;
835835
}
836+
/* Clamp outer size to remaining packet bytes so inner parses are bounded */
837+
if (packet != NULL && packet->pos < packet->size &&
838+
sensitive->size > (UINT16)(packet->size - packet->pos)) {
839+
sensitive->size = (UINT16)(packet->size - packet->pos);
840+
}
836841

837842
TPM2_Packet_ParseU16(packet, &sensitive->sensitiveArea.sensitiveType);
838843

src/tpm2_wrap.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,8 +1158,9 @@ int wolfTPM2_SpdmEnable(WOLFTPM2_DEV* dev)
11581158
if (rc == 0) {
11591159
rc = wolfTPM2_SPDM_Enable(dev->spdmCtx);
11601160
}
1161-
/* Restore previous session[0] state */
1161+
/* Restore previous session[0] state and clear the stack copy */
11621162
XMEMCPY(&dev->session[0], &saveSess, sizeof(dev->session[0]));
1163+
TPM2_ForceZero(&saveSess, sizeof(saveSess));
11631164
return rc;
11641165
}
11651166

@@ -1177,8 +1178,9 @@ int wolfTPM2_SpdmDisable(WOLFTPM2_DEV* dev)
11771178
if (rc == 0) {
11781179
rc = wolfTPM2_SPDM_Disable(dev->spdmCtx);
11791180
}
1180-
/* Restore previous session[0] state */
1181+
/* Restore previous session[0] state and clear the stack copy */
11811182
XMEMCPY(&dev->session[0], &saveSess, sizeof(dev->session[0]));
1183+
TPM2_ForceZero(&saveSess, sizeof(saveSess));
11821184
return rc;
11831185
}
11841186

@@ -1586,8 +1588,9 @@ int wolfTPM2_SpdmNationsIdentityKeySet(WOLFTPM2_DEV* dev, int set)
15861588
}
15871589
}
15881590

1589-
/* Restore previous session[0] state */
1591+
/* Restore previous session[0] state and clear the stack copy */
15901592
XMEMCPY(&dev->session[0], &saveSess, sizeof(dev->session[0]));
1593+
TPM2_ForceZero(&saveSess, sizeof(saveSess));
15911594

15921595
return rc;
15931596
}
@@ -2133,10 +2136,14 @@ static int wolfTPM2_EncryptSecret_ECC(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* tpm
21332136
r, &a, &prime, 1);
21342137
}
21352138
if (rc == 0) {
2136-
/* export shared secret x - constant-time fixed-size export avoids
2137-
* leaking the leading-zero count of the ECDH shared secret via
2138-
* data-dependent offsets */
2139+
/* export shared secret x - fixed-size export avoids leaking the
2140+
* leading-zero count of the ECDH shared secret via data-dependent
2141+
* offsets */
2142+
#ifdef WOLFSSL_HAVE_SP_ECC
21392143
rc = mp_to_unsigned_bin_len_ct(r->x, secretPoint.point.x.buffer, keySz);
2144+
#else
2145+
rc = mp_to_unsigned_bin_len(r->x, secretPoint.point.x.buffer, keySz);
2146+
#endif
21402147
secretPoint.point.x.size = keySz;
21412148
}
21422149
if (rc == 0) {

0 commit comments

Comments
 (0)