Skip to content

Commit d873b5e

Browse files
authored
Merge pull request #455 from aidangarske/fix/sha3-cryptocb-fallback-state
Restore SHA3 client state when the server cannot offload
2 parents 13521e5 + 2d1f1c1 commit d873b5e

1 file changed

Lines changed: 49 additions & 4 deletions

File tree

src/wh_client_crypto.c

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8695,11 +8695,34 @@ static int _Sha3FinalResponse(whClientContext* ctx, wc_Sha3* sha,
86958695
return ret;
86968696
}
86978697

8698+
/* Snapshot of the streaming state the offload path mutates: the Keccak
8699+
* state and the locally buffered partial block. */
8700+
typedef struct {
8701+
uint64_t s[25];
8702+
uint8_t t[WC_SHA3_224_BLOCK_SIZE]; /* largest block size: 144 */
8703+
uint32_t i;
8704+
} _Sha3SavedState;
8705+
8706+
static void _Sha3SaveState(const wc_Sha3* sha, _Sha3SavedState* saved)
8707+
{
8708+
saved->i = sha->i;
8709+
memcpy(saved->s, sha->s, sizeof(saved->s));
8710+
memcpy(saved->t, sha->t, sizeof(saved->t));
8711+
}
8712+
8713+
static void _Sha3RestoreState(wc_Sha3* sha, const _Sha3SavedState* saved)
8714+
{
8715+
sha->i = (uint8_t)saved->i;
8716+
memcpy(sha->s, saved->s, sizeof(saved->s));
8717+
memcpy(sha->t, saved->t, sizeof(saved->t));
8718+
}
8719+
86988720
static int _Sha3Oneshot(whClientContext* ctx, wc_Sha3* sha,
86998721
const whSha3Variant* v, const uint8_t* in,
87008722
uint32_t inLen, uint8_t* out)
87018723
{
8702-
int ret = WH_ERROR_OK;
8724+
int ret = WH_ERROR_OK;
8725+
_Sha3SavedState saved;
87038726

87048727
/* _Sha3UpdatePerCallCapacity (below) reads sha->i, so validate sha here
87058728
* rather than relying on the lower-level helper's NULL check. */
@@ -8713,6 +8736,11 @@ static int _Sha3Oneshot(whClientContext* ctx, wc_Sha3* sha,
87138736
return WH_ERROR_BADARGS;
87148737
}
87158738

8739+
/* A server without SHA3 answers NOT_COMPILED_IN, which wolfCrypt maps to
8740+
* CRYPTOCB_UNAVAILABLE and re-hashes the same input in software. Snapshot
8741+
* so that fallback cannot absorb any of it twice. */
8742+
_Sha3SaveState(sha, &saved);
8743+
87168744
if (in != NULL && inLen > 0) {
87178745
uint32_t consumed = 0;
87188746
while (ret == WH_ERROR_OK && consumed < inLen) {
@@ -8745,6 +8773,12 @@ static int _Sha3Oneshot(whClientContext* ctx, wc_Sha3* sha,
87458773
} while (ret == WH_ERROR_NOTREADY);
87468774
}
87478775
}
8776+
8777+
/* Leave sha as the caller passed it so a fallback starts clean. */
8778+
if (ret != WH_ERROR_OK) {
8779+
_Sha3RestoreState(sha, &saved);
8780+
}
8781+
87488782
return ret;
87498783
}
87508784

@@ -9135,14 +9169,19 @@ static int _Sha3DmaOneshot(whClientContext* ctx, wc_Sha3* sha,
91359169
const whSha3Variant* v, const uint8_t* in,
91369170
uint32_t inLen, uint8_t* out)
91379171
{
9138-
int ret = WH_ERROR_OK;
9172+
int ret = WH_ERROR_OK;
9173+
_Sha3SavedState saved;
91399174

91409175
/* Mirror _Sha3DmaUpdateRequest's invariant: skipping the update branch on
9141-
* (in == NULL && inLen != 0) would silently digest the current state. */
9142-
if (in == NULL && inLen != 0) {
9176+
* (in == NULL && inLen != 0) would silently digest the current state.
9177+
* sha is validated here since _Sha3SaveState dereferences it below. */
9178+
if (sha == NULL || (in == NULL && inLen != 0)) {
91439179
return WH_ERROR_BADARGS;
91449180
}
91459181

9182+
/* Same fallback hazard as _Sha3Oneshot: snapshot before mutating. */
9183+
_Sha3SaveState(sha, &saved);
9184+
91469185
if (in != NULL && inLen > 0) {
91479186
bool sent = false;
91489187
ret = _Sha3DmaUpdateRequest(ctx, sha, v, in, inLen, &sent);
@@ -9160,6 +9199,12 @@ static int _Sha3DmaOneshot(whClientContext* ctx, wc_Sha3* sha,
91609199
} while (ret == WH_ERROR_NOTREADY);
91619200
}
91629201
}
9202+
9203+
/* Leave sha as the caller passed it so a fallback starts clean. */
9204+
if (ret != WH_ERROR_OK) {
9205+
_Sha3RestoreState(sha, &saved);
9206+
}
9207+
91639208
return ret;
91649209
}
91659210

0 commit comments

Comments
 (0)