Conversation
There was a problem hiding this comment.
Pull request overview
Addresses several findings from the wolfSSL static analyzer across terminal handling, SFTP/FatFS file open logic, agent signing key setup, and SSHD authentication cleanup to improve correctness and safety.
Changes:
- Fixes a missing
breakin control-sequence handling to prevent unintended switch fallthrough. - Updates SFTP/FatFS open-mode handling and corrects an operator-precedence issue in Win32 authentication.
- Adds missing crypto initialization/checks (ECC init before import, check
wc_InitRsaKey()return) and securely zeroes plaintext password buffers before free.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/wolfterm.c |
Adds missing break to stop unintended fallthrough in CSI J handling. |
src/wolfsftp.c |
Initializes mode and adjusts flag tests for FatFS open-mode selection. |
src/agent.c |
Adds unused-parameter suppression in stubs; adds RSA init return check and ECC init before key import. |
apps/wolfsshd/auth.c |
Zeroes plaintext password copy before freeing; fixes precedence in LsaLookupAuthenticationPackage result check. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
1. Initialized mode variable to `FA_OPEN_EXISTING`, which is zero. 2. Changed the comparisons for the read/write flags to mask the read and write flags, then compare against the specific read or write flag. Setting the mode to RDWR would get handled only as read only. Affected function: ff_open.
Added parens around an assignment to a variable before it is compared to an expected value. Affected function: SetupUserTokenWin.
1. Call `wc_ecc_init()` on an ECC key before importing it. 2. Incidental: `PostLock()` and `PostUnlock()` needed their agent pointers tagged as unused. Affected functions: SignHashEcc. PostLock and PostUnlock.
Check the return value of `wc_InitRsaKey()`. It will initialize the structure provided the pointer is non-null. Since the key is on the stack, the later call to `wc_FreeRsaKey()` will succeed as well. Affected function: SignHashRsa.
Addded a break to the 'J' case of a switch statement that handles terminal display clearing for Windows. It was flowing into case 'K' without an explicit fallthrough tag. Affected function: wolfSSH_DoControlSeq.
When a copy of the user's password is freed, it wasn't getting force zeroed. It might still exist in the heap after getting freed. Added a call to `ForceZero()`. Affected function: CheckPasswordUnix.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
src/agent.c:702
- If
wc_InitRsaKey()fails (i.e.,ret != 0), the code still falls through to theencSigSz <= 0check (sinceencSigSzremains 0) and overwritesretwithWS_CRYPTO_FAILED. This loses the original failure code and can misreport the root cause. Suggestion: handle thewc_InitRsaKey()error via an early return (or preserveretand skip the encode/signature error mapping when init fails), so init failures aren’t masked as “Bad Encode Sig.”
int encSigSz = 0;
int ret = 0;
ret = wc_InitRsaKey(&key, heap);
if (ret == 0) {
mp_read_unsigned_bin(&key.n, rawKey->n, rawKey->nSz);
mp_read_unsigned_bin(&key.e, rawKey->e, rawKey->eSz);
mp_read_unsigned_bin(&key.d, rawKey->d, rawKey->dSz);
mp_read_unsigned_bin(&key.p, rawKey->p, rawKey->pSz);
mp_read_unsigned_bin(&key.q, rawKey->q, rawKey->qSz);
mp_read_unsigned_bin(&key.u, rawKey->iqmp, rawKey->iqmpSz);
encSigSz = wc_EncodeSignature(encSig, digest, digestSz,
wc_HashGetOID(hashType));
}
if (encSigSz <= 0) {
WLOG(WS_LOG_DEBUG, "Bad Encode Sig");
ret = WS_CRYPTO_FAILED;
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| if ((flag & WOLFSSH_O_RDWR) == WOLFSSH_O_RDONLY) { | ||
| mode = FA_READ; | ||
| } | ||
| else if ((flag & WOLFSSH_O_RDWR) == WOLFSSH_O_RDWR) { | ||
| mode = FA_READ | FA_WRITE; | ||
| } | ||
| else if ((flag & WOLFSSH_O_RDWR) == WOLFSSH_O_WRONLY) { | ||
| mode = FA_WRITE; | ||
| } | ||
| else { | ||
| return -1; | ||
| } | ||
|
|
||
| } else if (flag & WOLFSSH_O_RDWR) { | ||
| if ((flag & WOLFSSH_O_CREAT) && | ||
| (flag & WOLFSSH_O_TRUNC)) { | ||
| mode = FA_READ | FA_WRITE | FA_CREATE_ALWAYS; | ||
|
|
||
| } else if ((flag & WOLFSSH_O_CREAT) && | ||
| (flag & WOLFSSH_O_APPEND)) { | ||
| mode = FA_READ | FA_WRITE | FA_CREATE_NEW | FA_OPEN_APPEND; | ||
|
|
||
| } else { | ||
| mode = AM_ARC; | ||
| if ((flag & (WOLFSSH_O_WRONLY | WOLFSSH_O_CREAT)) | ||
| == (WOLFSSH_O_WRONLY | WOLFSSH_O_CREAT)) { | ||
| if (flag & WOLFSSH_O_TRUNC) { | ||
| mode |= FA_CREATE_ALWAYS; | ||
| } | ||
| } else if (flag & WOLFSSH_O_WRONLY) { | ||
| if ((flag & WOLFSSH_O_CREAT) && | ||
| (flag & WOLFSSH_O_TRUNC)) { | ||
| mode = FA_READ | FA_CREATE_ALWAYS | FA_WRITE; | ||
| } else if ((flag & WOLFSSH_O_CREAT) && | ||
| (flag & WOLFSSH_O_APPEND)) { | ||
| mode = FA_READ | FA_WRITE | FA_CREATE_NEW | FA_OPEN_APPEND; | ||
| else if (flag & WOLFSSH_O_APPEND) { | ||
| mode |= FA_CREATE_NEW | FA_OPEN_APPEND; | ||
| } | ||
| } else { | ||
| return -1; | ||
| } |
There was a problem hiding this comment.
The access-mode decoding is inconsistent with the prior bit-test logic and can produce incorrect behavior. Masking with WOLFSSH_O_RDWR and then comparing to WOLFSSH_O_RDONLY / WOLFSSH_O_WRONLY is only correct if WOLFSSH_O_RDWR is an “access-mode mask” (like POSIX O_ACCMODE); if WOLFSSH_O_RDONLY/_WRONLY/_RDWR are independent bits (as implied by the previous flag & WOLFSSH_O_* checks), the WRONLY/RDONLY branches may never match and the function can incorrectly return -1. Also, create/trunc/append handling now only applies to (WRONLY|CREAT) and no longer applies to RDWR|CREAT paths that previously set create flags. Suggestion: derive an access-mode value using a dedicated mask (e.g., WOLFSSH_O_ACCMODE or an explicit (WOLFSSH_O_RDONLY|WOLFSSH_O_WRONLY|WOLFSSH_O_RDWR) mask) and apply the create/trunc/append logic for both WRONLY and RDWR where appropriate (matching the previous behavior).
Fix some bugs found by the wolfSSL static analyzer: