Skip to content

Commit 481c67f

Browse files
authored
Merge pull request #571 from aidangarske/fenrir-fixes-9161-9162-9187
Fix wolfCrypt refcount race P521 primary derivation and policy session auth bypass
2 parents 46d2d33 + 83bc945 commit 481c67f

3 files changed

Lines changed: 119 additions & 15 deletions

File tree

src/fwtpm/fwtpm_command.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16811,6 +16811,10 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
1681116811
else if (entityH == TPM_RH_LOCKOUT) {
1681216812
authPolicy = &ctx->lockoutPolicy;
1681316813
}
16814+
/* PCR handles: check PCR_SetAuthPolicy-assigned policy */
16815+
else if (entityH <= PCR_LAST) {
16816+
authPolicy = &ctx->pcrPolicy[entityH - PCR_FIRST];
16817+
}
1681416818

1681516819
/* If entity has a non-empty authPolicy, it must match */
1681616820
if (authPolicy != NULL && authPolicy->size > 0) {
@@ -16870,6 +16874,18 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
1687016874
TPM_ST_NO_SESSIONS, TPM_RC_POLICY_FAIL);
1687116875
return TPM_RC_SUCCESS;
1687216876
}
16877+
else if (authPolicy == NULL) {
16878+
/* A policy session cannot authorize a handle whose authPolicy
16879+
* cannot be resolved (for example hash/sign sequence handles);
16880+
* fail closed per TPM 2.0 Part 1 Sec. 19.7. */
16881+
#ifdef DEBUG_WOLFTPM
16882+
printf("fwTPM: Policy session rejected for handle 0x%x with "
16883+
"unresolved authPolicy (CC=0x%x)\n", entityH, cmdCode);
16884+
#endif
16885+
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
16886+
TPM_ST_NO_SESSIONS, TPM_RC_POLICY_FAIL);
16887+
return TPM_RC_SUCCESS;
16888+
}
1687316889
}
1687416890
}
1687516891

src/fwtpm/fwtpm_crypto.c

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,53 @@ TPM_RC FwGenerateEccKey(WC_RNG* rng,
572572
/* ================================================================== */
573573

574574
#ifdef HAVE_ECC
575+
/* Constant-time compare of two big-endian byte arrays of equal length.
576+
* Returns 1 when a < b, otherwise 0. */
577+
static int FwCtLessBE(const byte* a, const byte* b, int len)
578+
{
579+
int i;
580+
unsigned int borrow = 0;
581+
for (i = len - 1; i >= 0; i--) {
582+
unsigned int diff = (unsigned int)a[i] - (unsigned int)b[i] - borrow;
583+
borrow = (diff >> 8) & 1u;
584+
}
585+
return (int)borrow;
586+
}
587+
588+
/* Load the curve order into a big-endian, keySz-padded buffer and report its
589+
* bit length, used to bound and mask the derived scalar. */
590+
static TPM_RC FwEccGetCurveOrder(int wcCurve, byte* orderBuf, int keySz,
591+
int* orderBits)
592+
{
593+
TPM_RC rc = TPM_RC_SUCCESS;
594+
int idx;
595+
const ecc_set_type* dp;
596+
mp_int order;
597+
598+
idx = wc_ecc_get_curve_idx(wcCurve);
599+
if (idx < 0) {
600+
return TPM_RC_CURVE;
601+
}
602+
dp = wc_ecc_get_curve_params(idx);
603+
if (dp == NULL) {
604+
return TPM_RC_CURVE;
605+
}
606+
if (mp_init(&order) != MP_OKAY) {
607+
return TPM_RC_FAILURE;
608+
}
609+
if (mp_read_radix(&order, dp->order, MP_RADIX_HEX) != MP_OKAY) {
610+
rc = TPM_RC_FAILURE;
611+
}
612+
if (rc == 0) {
613+
*orderBits = mp_count_bits(&order);
614+
if (mp_to_unsigned_bin_len(&order, orderBuf, keySz) != MP_OKAY) {
615+
rc = TPM_RC_FAILURE;
616+
}
617+
}
618+
mp_clear(&order);
619+
return rc;
620+
}
621+
575622
/* Derive ECC primary key from hierarchy seed per TPM 2.0 Part 1 Section 26.3.
576623
* d = KDFa(nameAlg, seed, "ECC", hashUnique, counter, keySz*8)
577624
* Q = d * G
@@ -596,6 +643,8 @@ TPM_RC FwDeriveEccPrimaryKey(TPMI_ALG_HASH nameAlg,
596643
int i;
597644
int allZero;
598645
volatile byte orAccum;
646+
byte orderBuf[MAX_ECC_BYTES];
647+
int orderBits = 0;
599648

600649
FWTPM_ALLOC_VAR(eccKey, ecc_key);
601650

@@ -604,6 +653,12 @@ TPM_RC FwDeriveEccPrimaryKey(TPMI_ALG_HASH nameAlg,
604653
return TPM_RC_CURVE;
605654
}
606655

656+
rc = FwEccGetCurveOrder(wcCurve, orderBuf, keySz, &orderBits);
657+
if (rc != 0) {
658+
FWTPM_FREE_VAR(eccKey);
659+
return rc;
660+
}
661+
607662
/* Derive private scalar d via KDFa, retry if out of range */
608663
while (!valid && counter < 100) {
609664
FwStoreU32BE(counterBuf, counter);
@@ -615,14 +670,18 @@ TPM_RC FwDeriveEccPrimaryKey(TPMI_ALG_HASH nameAlg,
615670
rc = TPM_RC_FAILURE;
616671
break;
617672
}
618-
/* Constant-time check d != 0 (all zeros) */
673+
/* Mask unused high bits so the candidate matches the order bit length */
674+
if ((orderBits & 7) != 0) {
675+
dBuf[0] &= (byte)((1u << (orderBits & 7)) - 1u);
676+
}
677+
/* Constant-time check 0 < d < order */
619678
orAccum = 0;
620679
for (i = 0; i < keySz; i++) {
621680
orAccum |= dBuf[i];
622681
}
623682
allZero = (orAccum == 0);
624-
if (!allZero) {
625-
valid = 1; /* Accept — range check done by import */
683+
if (!allZero && FwCtLessBE(dBuf, orderBuf, keySz)) {
684+
valid = 1;
626685
}
627686
counter++;
628687
}

src/tpm2.c

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,14 @@ static inline int TPM2_WolfCrypt_Init(void)
690690
{
691691
int rc = 0;
692692

693+
#if !defined(WOLFTPM_NO_LOCK) && !defined(SINGLE_THREADED) && \
694+
defined(WOLFSSL_MUTEX_INITIALIZER)
695+
/* gHwLock is statically initialized, so it can guard the reference count
696+
* before wolfCrypt is initialized */
697+
if (wc_LockMutex(&gHwLock) != 0)
698+
return TPM_RC_FAILURE;
699+
#endif
700+
693701
/* track reference count for wolfCrypt initialization */
694702
if (gWolfCryptRefCount == 0) {
695703
#ifdef DEBUG_WOLFSSL
@@ -710,8 +718,40 @@ static inline int TPM2_WolfCrypt_Init(void)
710718
}
711719
gWolfCryptRefCount++;
712720

721+
#if !defined(WOLFTPM_NO_LOCK) && !defined(SINGLE_THREADED) && \
722+
defined(WOLFSSL_MUTEX_INITIALIZER)
723+
wc_UnLockMutex(&gHwLock);
724+
#endif
725+
713726
return rc;
714727
}
728+
729+
static inline void TPM2_WolfCrypt_Cleanup(void)
730+
{
731+
#if !defined(WOLFTPM_NO_LOCK) && !defined(SINGLE_THREADED) && \
732+
defined(WOLFSSL_MUTEX_INITIALIZER)
733+
int locked = (wc_LockMutex(&gHwLock) == 0);
734+
#endif
735+
736+
/* track wolf initialize reference count in wolfTPM. wolfCrypt does not
737+
* properly track reference count in v4.1 or older releases */
738+
gWolfCryptRefCount--;
739+
if (gWolfCryptRefCount < 0)
740+
gWolfCryptRefCount = 0;
741+
if (gWolfCryptRefCount == 0) {
742+
#if !defined(WOLFTPM_NO_LOCK) && !defined(SINGLE_THREADED) && \
743+
!defined(WOLFSSL_MUTEX_INITIALIZER)
744+
wc_FreeMutex(&gHwLock);
745+
#endif
746+
wolfCrypt_Cleanup();
747+
}
748+
749+
#if !defined(WOLFTPM_NO_LOCK) && !defined(SINGLE_THREADED) && \
750+
defined(WOLFSSL_MUTEX_INITIALIZER)
751+
if (locked)
752+
wc_UnLockMutex(&gHwLock);
753+
#endif
754+
}
715755
#endif
716756

717757
/******************************************************************************/
@@ -957,18 +997,7 @@ TPM_RC TPM2_Cleanup(TPM2_CTX* ctx)
957997
}
958998
#endif
959999

960-
/* track wolf initialize reference count in wolfTPM. wolfCrypt does not
961-
* properly track reference count in v4.1 or older releases */
962-
gWolfCryptRefCount--;
963-
if (gWolfCryptRefCount < 0)
964-
gWolfCryptRefCount = 0;
965-
if (gWolfCryptRefCount == 0) {
966-
#if !defined(WOLFTPM_NO_LOCK) && !defined(SINGLE_THREADED) && \
967-
!defined(WOLFSSL_MUTEX_INITIALIZER)
968-
wc_FreeMutex(&gHwLock);
969-
#endif
970-
wolfCrypt_Cleanup();
971-
}
1000+
TPM2_WolfCrypt_Cleanup();
9721001
#endif /* !WOLFTPM2_NO_WOLFCRYPT */
9731002

9741003
#if (defined(WOLFTPM_LINUX_DEV) || defined(WOLFTPM_LINUX_DEV_AUTODETECT)) \

0 commit comments

Comments
 (0)