- add sftp_retry_remove()/sftp_retry_close() so Close and Remove are
driven to completion instead of abandoned mid-operation
- split the retry predicate: Open and SendWritePacket keep state only on
WS_WANT_READ/WS_WANT_WRITE, LS adds WS_REKEYING, Close and Remove gate
on NoticeError()
- assert the staging close; keep the post-read cleanup best effort, as
the reads are skipped rather than completed on WS_REKEYING
- route the WOLFSSH_TEST_INTERNAL write cleanup through the helpers
- shrink the staging chunk to 512 bytes
- Clamp the staging write chunk to the bytes remaining and derive the
try cap from the chunk count, so the loop lands exactly on
WOLFSSH_MAX_SFTP_RW for any value of the macro.
- Retry the staging Open and the LS on WS_WANT_READ, WS_WANT_WRITE,
and WS_REKEYING, matching the rekey tolerance used elsewhere in the
function.
- Assert the staging Open, the LS, and the listing match rather than
keying the read block on them, so neither a failed create nor a
connection stuck in WANT/REKEYING until the try cap can drop the
read coverage without failing the test.
- Remove any stale file before the staging Open, so the reads never
target a file staged by a prior aborted run.
- Size the read buffer from WOLFSSH_MAX_SFTP_RW, the amount staged and
the largest amount read, instead of the listed file size, and drop
the listed-size guard on the 18 byte read.
- Guard the listing name compare against a NULL fName.
- Verify every read returns the staged fill byte, not just a valid
length; the check is a macro so a failure reports the calling
read's line.
- Opening the listing's first entry raced with tests/testsuite.test,
which creates and removes files in the same directory under
"make -j check"; the entry could be gone before the open.
- Stage the read target over SFTP, select it from the listing by name,
and remove it afterward.
- Check the listing with AssertNotNull; a missing entry used to skip
the whole test body.
- Track the scpFileName allocation size in a new scpFileNameCap field,
so GetScpFileName() and ScpCheckForRename() reuse the buffer whenever
the name plus its terminator fits, instead of testing against the
previous name length
- Pass scpFileNameCap to the send callback, which writes into
scpFileName and needs the capacity; scpFileNameSz is now the name
length on every path, including the source path
- Free and reallocate the transfer buffer in ScpSourceInit(), clearing
the size fields alongside the pointers they describe
- Wrap a long line in ScpProcessEntry()
- Add test_ScpGetFileName covering the reuse-vs-realloc branch, the
exact-fit boundary, a grow-by-one that catches an off-by-one in the
reuse condition, and a source-path buffer holding no name yet
- Add test_wolfSSH_SCP_RecursiveTwoFiles, a real "scp -r" transfer of
two files, covering the scpFileHeaderSent reset on the recursive
path added in the duplicate-header fix; it clears leftovers from an
aborted run up front and bounds its recv so a regression fails
instead of hanging. Not built on Windows, where a recursive transfer
through the default callbacks does not reproduce the sent file
- Gate header on new scpFileHeaderSent flag, not scpFileOffset==0
- A send callback returning 0 bytes first no longer re-sends header
- Skip zero-length SCP_SEND_FILE send to avoid empty CHANNEL_DATA
- Abort on a second consecutive 0-byte send callback return with file
data outstanding; skipping the send would otherwise spin
SCP_SEND_FILE -> SCP_TRANSFER with no socket I/O
- Reset offset/bufferedSz/flags in ScpSourceInit for connection reuse
- Document the WS_CallbackScpSend contract, including when a 0 return
is valid, next to the typedef
- Add test_wolfSSH_SCP_SendZeroFirst regression (func_args scp_send hook)
- Zero func_args in kex.c/testsuite.c so the new scp_send field is not read uninitialized
Issue: ZD-22176
- IdentifyAsn1Key() was called with a literal 1, so a public PEM decoded
by wc_PubKeyPemToDer() was run through the private-key decoders and
never identified.
- Add test_wolfSSH_ReadPublicKey_pem() covering a public RSA PEM read
through wolfSSH_ReadPublicKey_buffer(). The read itself only compiles
with WOLFSSH_TPM, so the test also asserts the isPrivate 0 vs 1
difference in IdentifyAsn1Key() directly, which every build runs.
Issue: F-7209
c[inSz-1] = 0 clobbered the last byte of the copied key data instead
of terminating the string after it, truncating public keys by one
character.
Issue: F-7205
- Add wolfSSH_FwdRemoteSetup/Cancel to request tcpip-forward
- Add SendGlobalRequestFwd to frame the request per RFC 4254
- Add portfwd -r reverse mode, driven by the fwd and req-success cbs
- Wait for the peer's reply before -R reports ready, and take the
bound port from it; with -f 0 that reply is the only source
- Accept -f 0 in reverse mode, where it asks the peer to pick the port
- Cancel names the port the peer bound, not the one requested, so a
peer keyed on its listener's port can still find it
- Add a req-failure cb so a refused forward is reported, not waited on
Issue: ZD-21867
- Charge abandoned keyboard INFO_REQUEST before method dispatch so a
peer can't dodge the cap; drop unused "counted" param.
- Exempt the opening "none" probe in DoUserAuthRequestNone() under
WOLFSSH_ALLOW_USERAUTH_NONE, matching ssh.h contract.
- unit.c: add keyboard restart, setup-rejection, and none-exemption
MaxAuthAttempts scenarios.
- api.c: assert "none" cipher/MAC accepted under WOLFSSH_ALLOW_NONE_CIPHER.
- Setters stored caller string verbatim; "none" cipher/MAC risked cleartext
- Add CheckAlgoList()/NameToIdType() to validate each token by category
- Set* now returns WS_INVALID_ALGO_ID on bad/NULL input, list unchanged
- "none" is rejected in the key list, and allowed for cipher/MAC only under
WOLFSSH_ALLOW_NONE_CIPHER
- Names unknown to the build are skipped rather than rejected, so a portable
superset list still works; a known name in the wrong category fails
- Reject empty list elements apart from one trailing comma, which would
otherwise reach KEXINIT as a zero-length name
- Give ID_NONE a block size so the none cipher no longer divides by zero in
BundlePacket(), and skip the zero-length key derivations it implies
- Treat an empty peer server-sig-algs as no extension rather than a fatal
parse error
- The "at least one X" guards checked the implementation macros but not the
soft-disable macros that gate joining the canned default list, so a build
whose only survivors are soft-disabled got an empty default list: KEXINIT
advertised nothing and CheckAlgoList() rejected it. Reachable as
-DWOLFSSH_NO_HMAC_SHA2_256 -DWOLFSSH_NO_HMAC_SHA2_512 and as
-DWOLFSSH_NO_AES_GCM -DWOLFSSH_NO_AES_CTR; both now fail at compile time
naming the soft-disable macro to define
- Zero MAC algorithms is already a hard #error, so assert the queried MAC
list in test_wolfSSH_SetAlgoList() rather than returning early, which was
hiding the KEX/KEY/CIPHER coverage behind an unreachable guard
Issue: 2474
Harden the partial-sequence reassembly in wolfSSH_DoControlSeq and fix an
escape-state leak in the wolfSSH_ConvertConsole OSC resume path
(USE_WINDOWS_API console handling).
- Tighten both escBuf partial-save branches to reject bufSz - *idx >=
WOLFSSL_MAX_ESCBUF before the WMEMCPY and log via WLOG. escBuf is
WOLFSSL_MAX_ESCBUF bytes, so a save of exactly that length fills it with
no room for later state; rejecting the boundary keeps the two branches
consistent and matches the resume check.
- Add the capacity guard to the initial-parse CSI save branch, which
previously copied into escBuf with no bound. In the default build getArgs
caps the advance below WOLFSSL_MAX_ESCBUF so the copy was already safe;
the guard prevents a custom WOLFSSH_MAX_CONSOLE_ARGS > WOLFSSL_MAX_ESCBUF
build from overflowing escBuf.
- Clear escState to WC_ESC_NONE when a resumed OSC sequence completes, not
just escBufSz. Without this escState stayed WS_ESC_OSC and the next call
re-entered OSC parsing on plain bytes instead of printing them.
Extend test_wolfSSH_ConvertConsole with a CSI sequence split across three
calls (ESC[ | args | command char), a trailing plain byte that must be
printed once state is cleared, and a single buffer whose CSI args run to
the end and complete on the next byte.
- Without the guard, inner loops short-circuit and WS_SUCCESS
is returned without any verification.
- Add test case covering the new and existing bad-arg paths.
Issue: F-409
1. Collect all the test function wrappers in internal.c to one location
at the end of the file.
2. Update API test to check other algos if RSA or ECDSA are disabled.
3. Added guarded tests TestClientBuffersIdempotent() for WOLFSSH_NO_RSA
and WOLFSSH_NO_ECDSA_SHA2_NISTP256. If both are set, the test is
skipped.
Replace rewind() with fseek(f, 0, SEEK_SET) in the test helper
function. rewind() internally clears errno, which scan-build flags
as overwriting a previously unchecked errno value. fseek() to
offset 0 is functionally equivalent without the implicit errno
reset.
Static analysis indicated the potential to double-free a pointer in the
`wolfSSH_CTX_UseCert_buffer()` test. Loading the second cert after
freeing the first cert could fail and the test cleanup would free the
pointer again. Just set pointer to null after freeing.
Instantiate a wolfSSH_AGENT_CTX before invoking wolfSSH_AGENT_SignRequest so the regression tests exercise the intended paths instead of failing with WS_AGENT_NULL_E.
Exercise agent write failures, non-signature responses, oversized signatures, and the happy path to cover the recent wolfSSH_AGENT_SignRequest hardening.