Skip to content

Apply checking of req_size in handlers#299

Merged
bigbrett merged 1 commit intowolfSSL:mainfrom
padelsbach:padelsbach/ret-size-checking
Mar 24, 2026
Merged

Apply checking of req_size in handlers#299
bigbrett merged 1 commit intowolfSSL:mainfrom
padelsbach:padelsbach/ret-size-checking

Conversation

@padelsbach
Copy link
Contributor

@padelsbach padelsbach commented Mar 13, 2026

Several functions in wh_server_she.c ignored the received payload length with (void)req_size;. This change adds size checking and associated unit tests.

@padelsbach padelsbach force-pushed the padelsbach/ret-size-checking branch 2 times, most recently from 2e741ac to fc0e2e2 Compare March 16, 2026 20:29
@padelsbach padelsbach marked this pull request as ready for review March 17, 2026 19:49
@padelsbach padelsbach requested a review from bigbrett March 17, 2026 19:49
@padelsbach padelsbach force-pushed the padelsbach/ret-size-checking branch from fc0e2e2 to c0ee8d4 Compare March 18, 2026 00:09
Copy link
Contributor

@bigbrett bigbrett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work. A few more issues I noticed, but getting closer.

@bigbrett bigbrett removed their assignment Mar 18, 2026
@padelsbach padelsbach force-pushed the padelsbach/ret-size-checking branch from c0ee8d4 to 3743349 Compare March 19, 2026 16:47
Copy link

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fenrir Automated Review — PR #299

Scan targets checked: wolfhsm-core-bugs, wolfhsm-src
Findings: 4

Medium (3)

Missing WH_SHE_ERC_KEY_NOT_AVAILABLE error translation in _LoadKey

File: src/wh_server_she.c:499-515
Function: _LoadKey
Category: Incorrect error handling

The refactoring of _LoadKey removed the else { ret = WH_SHE_ERC_KEY_NOT_AVAILABLE; } branch that previously translated a wh_Server_KeystoreReadKey failure into the SHE-spec-mandated WH_SHE_ERC_KEY_NOT_AVAILABLE error code. Now when the auth key read fails, the raw keystore error code propagates through instead of being mapped to the correct SHE error. This is inconsistent with all other handlers in this file (_EncEcb, _EncCbc, _DecEcb, _DecCbc, _GenerateMac, _VerifyMac, _ExportRamKey) which all preserve the WH_SHE_ERC_KEY_NOT_AVAILABLE translation after a wh_Server_KeystoreReadKey failure. The raw error code will be passed to _TranslateSheReturnCode(ret) for the response, which may not map it to KEY_NOT_AVAILABLE, and it is also returned directly from the function.

if (ret == 0) {
        keySz = sizeof(kdfInput);
        ret = wh_Server_KeystoreReadKey(server,
                                        WH_MAKE_KEYID(WH_KEYTYPE_SHE,
                                                      server->comm->client_id,
                                                      _PopAuthId(req.messageOne)),
                                        NULL, kdfInput, &keySz);
    }
    /* make K2 using AES-MP(authKey | WH_SHE_KEY_UPDATE_MAC_C) */
    if (ret == 0) {
        memcpy(kdfInput + keySz, _SHE_KEY_UPDATE_MAC_C,
               sizeof(_SHE_KEY_UPDATE_MAC_C));
        ret = _AesMp16(server, kdfInput, keySz + sizeof(_SHE_KEY_UPDATE_MAC_C),
                       tmpKey);
        if (ret != 0) {
            ret = WH_SHE_ERC_GENERAL_ERROR;
        }
    }

Recommendation: Add an else branch after wh_Server_KeystoreReadKey to translate the error, consistent with all other handlers:

    if (ret == 0) {
        keySz = sizeof(kdfInput);
        ret = wh_Server_KeystoreReadKey(server, ..., kdfInput, &keySz);
        if (ret != 0) {
            ret = WH_SHE_ERC_KEY_NOT_AVAILABLE;
        }
    }

Integer overflow in req_size validation can bypass bounds checks on 32-bit platforms

File: src/wh_server_she.c:1148-1157
Function: _EncEcb
Category: Integer overflows

The newly added size checks use expressions like req_size < (sizeof(req) + field) where field is a uint32_t derived from attacker-controlled req.sz. On 32-bit platforms (common for HSMs), sizeof(req) + field is computed in 32-bit size_t arithmetic and can wrap around to a small value when field is close to UINT32_MAX. If sizeof(req) and sizeof(resp) are both multiples of 16 (AES_BLOCK_SIZE), an attacker can craft req.sz such that both (sizeof(req) + field) and (sizeof(resp) + field) wrap to 0 or a small value, bypassing both the input and output buffer size checks. This would allow reading past req_packet and writing past resp_packet. The same pattern appears in _EncCbc, _DecEcb, and _DecCbc.

field = req.sz;
field -= (field % AES_BLOCK_SIZE);
if (req_size < (sizeof(req) + field)) {
    ret = WH_ERROR_BUFFER_SIZE;
}
else if ((sizeof(resp) + field) > WOLFHSM_CFG_COMM_DATA_LEN) {
    ret = WH_ERROR_BUFFER_SIZE;
}

Recommendation: Add an explicit upper-bound check on field (or req.sz) before the addition, e.g., if (field > WOLFHSM_CFG_COMM_DATA_LEN) as an early reject. Alternatively, cast operands to uint64_t or use a safe addition helper that detects overflow: if (field > SIZE_MAX - sizeof(req) || req_size < (sizeof(req) + field)).


Integer overflow in _VerifyMac second addition bypasses size check

File: src/wh_server_she.c:1509-1513
Function: _VerifyMac
Category: Integer overflows

The _VerifyMac function correctly checks for overflow in totalLen = req.messageLen + req.macLen with (totalLen < req.messageLen). However, the subsequent check req_size < (sizeof(req) + totalLen) has the same 32-bit integer overflow issue. When totalLen passes the first check (no wrap in the addition), it can still be close to UINT32_MAX (e.g., messageLen = 0x7FFFFFFF, macLen = 0x7FFFFFFF yields totalLen = 0xFFFFFFFE). On a 32-bit platform, sizeof(req) + 0xFFFFFFFE wraps to a small value, bypassing the bounds check. This could allow mac = message + req.messageLen to point past the request buffer, leading to an out-of-bounds read during CMAC verification.

totalLen = req.messageLen + req.macLen;
if ((totalLen < req.messageLen) ||
    (req_size < (sizeof(req) + totalLen))) {
    ret = WH_ERROR_BUFFER_SIZE;
}

Recommendation: Add an overflow check for the second addition as well: if ((totalLen > SIZE_MAX - sizeof(req)) || (req_size < (sizeof(req) + totalLen))). Alternatively, check totalLen > WOLFHSM_CFG_COMM_DATA_LEN before adding sizeof(req).


Low (1)

_LoadKey lost WH_SHE_ERC_KEY_NOT_AVAILABLE error mapping for KeystoreReadKey failure

File: src/wh_server_she.c:498-511
Function: _LoadKey
Category: SHE extension vulnerabilities

The old code explicitly mapped wh_Server_KeystoreReadKey failure to WH_SHE_ERC_KEY_NOT_AVAILABLE. The refactored code removes this mapping — when wh_Server_KeystoreReadKey fails, the raw internal error code now propagates through the function and is only translated at the end by _TranslateSheReturnCode(ret). If _TranslateSheReturnCode does not properly map all internal wolfHSM error codes to SHE-specific error codes, this could leak internal error code values to the client, providing information about the server's internal state. The old else { ret = WH_SHE_ERC_KEY_NOT_AVAILABLE; } block was removed without an equivalent replacement.

if (ret == 0) {
    keySz = sizeof(kdfInput);
    ret = wh_Server_KeystoreReadKey(server,
                                    WH_MAKE_KEYID(WH_KEYTYPE_SHE,
                                                  server->comm->client_id,
                                                  _PopAuthId(req.messageOne)),
                                    NULL, kdfInput, &keySz);
}
/* make K2 using AES-MP(authKey | WH_SHE_KEY_UPDATE_MAC_C) */
if (ret == 0) {
    ...

Recommendation: Either restore the explicit WH_SHE_ERC_KEY_NOT_AVAILABLE mapping after the wh_Server_KeystoreReadKey call (e.g., if (ret != 0) { ret = WH_SHE_ERC_KEY_NOT_AVAILABLE; }), or verify that _TranslateSheReturnCode correctly maps all possible internal error codes returned by wh_Server_KeystoreReadKey to appropriate SHE error codes.


This review was generated automatically by Fenrir. Findings are non-blocking.

@padelsbach padelsbach force-pushed the padelsbach/ret-size-checking branch from 3743349 to 883bcd4 Compare March 19, 2026 22:59
@padelsbach
Copy link
Contributor Author

Addressed the overflow possibility raised by @wolfSSL-Fenrir-bot. Will not fix the WH_SHE_ERC_KEY_NOT_AVAILABLE concerns based on comment above from Brett

Copy link

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fenrir Automated Review — PR #299

Scan targets checked: wolfhsm-core-bugs, wolfhsm-src
Findings: 2

Medium (1)

_LoadKey lost WH_SHE_ERC_KEY_NOT_AVAILABLE error mapping for auth key read failure

File: src/wh_server_she.c:497-523
Function: _LoadKey
Category: Incorrect error handling

The refactoring of _LoadKey removed the else { ret = WH_SHE_ERC_KEY_NOT_AVAILABLE; } branch that mapped wh_Server_KeystoreReadKey failures to the SHE-specified error code. Previously, if the auth key could not be read, ret was explicitly set to WH_SHE_ERC_KEY_NOT_AVAILABLE. In the new code, the raw error code from wh_Server_KeystoreReadKey propagates, and _TranslateSheReturnCode maps it to WH_SHE_ERC_GENERAL_ERROR instead of the correct WH_SHE_ERC_KEY_NOT_AVAILABLE. All other handlers that call wh_Server_KeystoreReadKey (_EncEcb, _EncCbc, _DecEcb, _DecCbc, _GenerateMac, _VerifyMac) correctly preserved the else { ret = WH_SHE_ERC_KEY_NOT_AVAILABLE; } pattern, making this an inconsistent copy-paste omission.

if (ret == 0) {
        keySz = sizeof(kdfInput);
        ret = wh_Server_KeystoreReadKey(server,
                                        WH_MAKE_KEYID(WH_KEYTYPE_SHE,
                                                      server->comm->client_id,
                                                      _PopAuthId(req.messageOne)),
                                        NULL, kdfInput, &keySz);
    }
    /* make K2 using AES-MP(authKey | WH_SHE_KEY_UPDATE_MAC_C) */
    if (ret == 0) {
        ...
        ret = _AesMp16(server, kdfInput, keySz + sizeof(_SHE_KEY_UPDATE_MAC_C),
                       tmpKey);
        if (ret != 0) {
            ret = WH_SHE_ERC_GENERAL_ERROR;
        }
    }
    /* Missing: else { ret = WH_SHE_ERC_KEY_NOT_AVAILABLE; } */

Recommendation: Add an else branch after the wh_Server_KeystoreReadKey call (or between the two if (ret == 0) blocks) to map keystore read failures to WH_SHE_ERC_KEY_NOT_AVAILABLE, matching the pattern used in all other SHE handlers:

if (ret == 0) {
    keySz = sizeof(kdfInput);
    ret = wh_Server_KeystoreReadKey(server, ..., NULL, kdfInput, &keySz);
    if (ret != 0) {
        ret = WH_SHE_ERC_KEY_NOT_AVAILABLE;
    }
}

Low (1)

_SetUid mixes ret == 0 and ret == WH_SHE_ERC_NO_ERROR guard conditions

File: src/wh_server_she.c:193-223
Function: _SetUid
Category: Logic errors

The PR introduced ret == 0 checks for the new buffer-size and translate guards, but the pre-existing memcpy guard still uses ret == WH_SHE_ERC_NO_ERROR. While WH_SHE_ERC_NO_ERROR is almost certainly defined as 0, the function now operates across two error-code domains (wolfHSM generic errors like WH_ERROR_BUFFER_SIZE and SHE-specific errors like WH_SHE_ERC_SEQUENCE_ERROR) and checks them inconsistently. If WH_SHE_ERC_NO_ERROR were ever redefined to a non-zero sentinel value, the memcpy guard would silently break. No other handler in this file mixes these two comparison styles.

if (ret == 0) {
        ret = wh_MessageShe_TranslateSetUidRequest(
            magic, (whMessageShe_SetUidRequest*)req_packet, &req);
    }

    if ((ret == 0) && (server->she->uidSet == 1)) {
        ret = WH_SHE_ERC_SEQUENCE_ERROR;
    }

    if (ret == WH_SHE_ERC_NO_ERROR) {
        memcpy(server->she->uid, req.uid, sizeof(req.uid));
        server->she->uidSet = 1;
    }

Recommendation: Change if (ret == WH_SHE_ERC_NO_ERROR) to if (ret == 0) for consistency with the other guards in the same function, or change all the ret == 0 checks to ret == WH_SHE_ERC_NO_ERROR.


This review was generated automatically by Fenrir. Findings are non-blocking.

@bigbrett bigbrett merged commit 34b59ab into wolfSSL:main Mar 24, 2026
51 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants