@@ -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+
86988720static 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