ConfirmedCWE-385 — Missing State Tracking
[Bug]: Reinit succeeds from INIT state (before any Update)
View Upstream Issuegitcode.com/openHiTLS/openhitls/issues/157CWE:CWE-385 — Missing State Tracking
Repository:openHiTLS
Date:2026-05-19
Affected Version:*
Component:hmac
Reporter:Toan
Affected Files
crypto/hmac/src/hmac.cSummary
CRYPT_HMAC_Reinit is intended to reset the running hash back to the post-Init baseline, allowing the same key to be reused for a new message without calling Init again. Per the state model, it should only be valid from UPDATE or FINAL state — after at least one Update or Final has been called. However, it succeeds when called immediately after Init, before any Update.
Vulnerable Code
// crypto/hmac/src/hmac.c:226
int32_t CRYPT_HMAC_Reinit(CRYPT_HMAC_Ctx *ctx)
{
if (ctx == NULL || ctx->method.copyCtx == NULL) { // only checks pointers
...
}
ctx->method.copyCtx(ctx->mdCtx, ctx->iCtx);
return CRYPT_SUCCESS; // always succeeds once Init has run
}
The CRYPT_HMAC_Ctx struct has no state field. Reinit only checks that copyCtx is non-NULL, which is true as soon as Init has run, so it succeeds from any post-Init state including INIT.
Reference model defines:
Reinit is valid from: UPDATE, FINAL
Reinit is invalid from: NEW, INIT, DEINIT
Reproducer
CRYPT_HMAC_Init(mac, key, 32); // state: INIT
int32_t ret = CRYPT_HMAC_Reinit(mac); // reference model: should return ERR_STATE
ASSERT_NE(ret, CRYPT_SUCCESS); // FAILS: ret == CRYPT_SUCCESS (0)
Trigger Conditions
- Caller initializes an HMAC context with
CRYPT_HMAC_Init - Caller calls
CRYPT_HMAC_Reinitbefore anyUpdateorFinal Reinitsucceeds (returnsCRYPT_SUCCESS) instead of returning a state error- Caller cannot detect incorrect API usage
Impact
- State machine violation:
ReinitfromINITstate is a no-op (iCtxandmdCtxalready hold the same state), so output is still correct — but the state machine contract is broken - No misuse detection: Callers cannot detect incorrect usage patterns; silent success masks bugs in caller code
- Lower severity than CRYPTO-004: No wrong output, but violated invariant prevents callers from catching errors
Suggested Fix
Add a hasData flag to CRYPT_HMAC_Ctx that is set after the first Update call and cleared by Init and Deinit. Reinit checks the flag before proceeding:
// crypto/hmac/src/hmac.c — struct addition
struct HMAC_Ctx {
CRYPT_MAC_AlgId hmacId;
EAL_MdMethod method;
void *mdCtx;
void *oCtx;
void *iCtx;
bool hasData; // ← ADD: set true on first Update, cleared by Init/Deinit
};
// crypto/hmac/src/hmac.c — Reinit fix
int32_t CRYPT_HMAC_Reinit(CRYPT_HMAC_Ctx *ctx)
{
if (ctx == NULL || ctx->method.copyCtx == NULL ||
ctx->mdCtx == NULL || ctx->iCtx == NULL ||
!ctx->hasData) { // ← ADD check
BSL_ERR_PUSH_ERROR(CRYPT_EAL_ERR_STATE);
return CRYPT_EAL_ERR_STATE;
}
ctx->method.copyCtx(ctx->mdCtx, ctx->iCtx);
ctx->hasData = false; // ← RESET for next round
return CRYPT_SUCCESS;
}