Commit Graph

2853 Commits (8f5d31a2c6952a34ca17df1885eb299136bfeb80)

Author SHA1 Message Date
John Safranek 8f5d31a2c6 Add wolfssh-options build option probe
Test scripts sniff the build by grepping usage text, config.log and daemon
logs. This prints the enabled build options for them to check instead.
2026-08-19 16:55:00 -07:00
Paul Adelsbach b92e57ab4c PR feedback 2026-08-19 16:53:24 -07:00
Paul Adelsbach b1cd689ecc F-8824: enable config files without trailing newline 2026-08-19 16:53:24 -07:00
Yosuke Shimizu f530d32548 Load every PEM block in a root CA buffer
- LoadRootCaPemBuffer() loads every block a PEM CA buffer holds as a
  root CA, skipping the ones that fail. It returns WS_SUCCESS when
  any loaded, WS_PARSE_E when all failed, and WS_BAD_FILE_E when the
  buffer holds no block.
- A block runs header to footer with the next header capping the
  footer search, so wc_PemToDer() gets the block rather than the rest
  of the buffer. A header that nothing closes is skipped and the walk
  resumes at its end; each form's header is re-sought only from
  behind the one just read.
- A block takes the plain or the trusted form, whichever header leads
  picking the type. FindInBuffer() searches a length-delimited
  buffer, so an embedded NUL does not end the search.
- wolfSSH_ProcessBuffer() routes a PEM BUFTYPE_CA there and, like
  DoPemCert(), gives WS_BAD_FILETYPE_E for the trusted form as a
  certificate; SniffCertForm() reads its header as X.509 PEM.
- internal.h defines WOLFSSH_HAVE_TRUSTED_CERT_PEM under
  WOLFSSH_CERTS with wolfSSL 5.8.0 or newer and declares
  IsTrustedCertPem(); ssh.h documents the cert buffer calls.
- tests/api.c adds catBuffers(), makeTrustedPem() and
  assertCaInstalled(), with tests for the bundle, trusted file and
  trusted ReadCert paths.
2026-08-19 14:54:06 -07:00
Yosuke Shimizu 5ae0cc4c93 port: resolve the full SFTP offset in the Harmony and Zephyr ports
- Assemble the split offset with wResolveOffset() in the Harmony wPread
  and wPwrite, and seek with the resolved value.
- Assemble the split offset with wResolveOffset() in the Zephyr wPread
  and wPwrite, and seek with the resolved value.
- Define WOLFSSH_MAX_FILE_OFFSET as 0x7FFFFFFF in the Harmony block, so
  the ceiling comes from SYS_FS_FileSeek's int32_t offset rather than
  from off_t.
- Add test_PreadPwriteOffsetCeiling() covering ports whose seek type
  cannot reach 4 GiB, including a read back at an in-range offset.
- Add test_ResolveOffset() covering offset assembly, both sides of the
  ceiling, and the NULL guards.

Issue: F-8823
2026-08-18 15:01:39 -07:00
Paul Adelsbach 2b2e86fb4f Move path to end of log line to avoid early truncation of the log 2026-08-18 14:28:40 -07:00
John Safranek dac55852e3 Use wolfCrypt's Base16_Decode in test.h when it is available
- test.h's static Base16_Decode collides with wolfSSL's public one
    when coding.h lands first, breaking --enable-tpm builds.
  - Include coding.h in test.h, keeping the local copy only when
    WOLFSSL_BASE16 is absent; --enable-wolfssh alone does not set it.
  - api.c includes coding.h too, dropping its hand-declared
    Base64_Encode_NoNl, which would now be a duplicate.
2026-08-16 12:30:15 -07:00
Yosuke Shimizu 5c92896d03 Run the API tests in the TPM CI job
- No job compiled a wolfSSH test binary with WOLFSSH_TPM defined, so a
  test guarded on it compiled out everywhere and could not gate a
  merge. This job enables TPM but only builds; the jobs that run make
  check do not enable it.
- Add a make check step. automake's check-am builds every check_PROGRAM
  regardless of the TESTS override, so this is the only job that
  compiles wolfSSH's tests with TPM support.
- Override TESTS to run only tests/api.test, the one suite with
  TPM-specific tests. kex.test also aborts in the example client, which
  demands -K in a TPM build.
- Restrict it to one matrix cell. The 2x2x2 matrix varies the simulator
  and the host key, neither of which these tests touch.
- Assert -DWOLFSSH_TPM in AM_CPPFLAGS first. A build without it
  compiles the guarded tests out and still exits 0, a hollow pass.
- Dump tests/api.log on failure and archive it.
2026-08-14 14:35:24 -07:00
Yosuke Shimizu 1644bb773d Accept exact-fit ScpBuffer in no-filesystem SCP send callback 2026-08-14 14:34:16 -07:00
Yosuke Shimizu 497da8a130 examples: use the selected algorithm for the default public key
- sftpclient passes userEcc to ClientUsePubKey(), and scpclient to
  both ClientSetPrivateKey() and ClientUsePubKey(), in place of a
  hardcoded 0.
- scpclient gains a userEcc; it and client default it to 1 under
  WOLFSSH_NO_RSA, as sftpclient already did.
- ClientSetPrivateKey() and ClientUsePubKey() name the missing
  algorithm on stderr and return WS_NOT_COMPILED when the built-in
  key they select is compiled out.
- Both skip the built-in load entirely when neither RSA nor ECC is
  compiled in, clearing the key size and type and returning success
  so password-only authentication still runs. ClientUsePubKey()'s
  buffer pointer moves inside the guard so it is not left unused.

Issue: F-8829
2026-08-14 14:32:15 -07:00
Yosuke Shimizu 2142821bc6 Stop wPread and wPwrite dropping the high offset word 2026-08-14 14:25:55 -07:00
Paul Adelsbach 326d181389 PR feedback: fix test issue with --disable-server --enable-sshclient 2026-08-13 14:36:28 -07:00
Paul Adelsbach aeb3c4e3d2 Fix build with --disable-server 2026-08-13 14:36:28 -07:00
Yosuke Shimizu e91ff50def Fix a one byte heap overflow in LoadTpmSshKey 2026-08-13 11:59:57 -07:00
David Garske 8cef200ebd Add CONTRIBUTING.md covering the contributor agreement and PR process 2026-08-13 09:53:09 -07:00
Yosuke Shimizu 255dd926d9 Adopt the certificate loading APIs in the examples and apps 2026-08-12 16:06:39 -07:00
Yosuke Shimizu ca6a036edc Replace the matching certificate slot instead of appending a duplicate 2026-08-12 15:43:01 -07:00
John Safranek 31ed01d050 Stop the client discarding the remote command
- keepOpen was hardcoded to 1, so the TERMINAL channel type was always
  set right after EXEC, freeing the command and reverting to a shell.
- Derive keepOpen from whether a command was given.
- Gate MODES_CLEAR() the same way. A remote command runs with no pty,
  so its LF terminated output needs OPOST left on.
- The SINGLE_THREADED guard is now unconditional, matching what it did
  when keepOpen was always 1.
- Remove -N. It was parsed into config.noCommand and read nowhere, and
  making it work needs a way to request no session at all.
- Add the optional command to the usage line.
- Reject a command of WOLFSSH_MAX_CHN_NAMESZ or longer. SetChannelType
  discards it and still returns WS_SUCCESS, so the client would send an
  exec request with no command string at all.
- Drop the I/O thread guard. With keepOpen derived from config.command,
  the condition was true for every input.

Issue: F-8816
2026-08-12 14:38:48 -06:00
Yosuke Shimizu 6579f59236 wolfsshd: base Match blocks on the global config and keep included ones 2026-08-11 18:13:34 -07:00
John Safranek ddd9c1a761 Guard IdentifyAsn1Key test on TEST_INTERNAL
- IdentifyAsn1Key is WOLFSSH_LOCAL, so the check and its DER blob
  only build when linking the test library.
2026-08-11 11:55:02 -05:00
Yosuke Shimizu 53538e8261 Report a failed PEM decode as WS_PARSE_E, not WS_BAD_FILE_E 2026-08-10 15:11:39 -07:00
Paul Adelsbach 0c355c31ac Enforce null termination in sshd unit tests 2026-08-10 15:07:59 -07:00
Emma Stensland 244c82c86d Add remaining ML-DSA composite signature algorithms 2026-08-10 14:51:37 -07:00
Emma Stensland 866f7392cd Add ML-DSA44-Ed25519 composite signature support 2026-08-10 14:51:37 -07:00
John Safranek b2b32cca51 tests: add test_ByteHighwater
- The byte-count branch of HighwaterCheck() had no coverage. Exercise
  the boundary at the mark, the once-per-epoch flag that keeps the
  callback from firing a second time, the receive side, and a mark of
  0 disabling the check.

Issue: F-6978
2026-08-10 13:53:08 -06:00
John Safranek 6793c3e273 internal: validate the ECC curve name in user auth
- DoUserAuthRequestEcc() skipped the curve name in the public key blob
  and imported the point with wc_ecc_import_x963(), which picks the
  curve from the point length, so the key did not have to be on the
  curve the declared algorithm names.
- Derive the curve from pk->publicKeyType with NameToId() and
  wcPrimeForId(), require the blob's curve name to equal
  PrimeNameForId() for that id, and import with
  wc_ecc_import_x963_ex() pinned to that curve.
- The import's error check sat outside the success guard, so it
  rewrote any earlier error as WS_CRYPTO_FAILED. Scope it to the
  import itself so the parse and algorithm-match errors keep their
  own codes.
- Add test_EccUserAuthCurveMismatch, which offers a blob naming one
  curve under another algorithm and expects the request to fail.

Issue: F-6979
2026-08-10 13:53:08 -06:00
John Safranek 75b3418c0a ssh.h: document the WS_CallbackPublicKeyCheck contract
- The callback is the client's only defense against a man in the
  middle, and 0 accepts the server host key, so a stub that defaults
  to "return 0" trusts whatever key is presented.
- State that the callback must match the key against a trust store,
  and point at ClientPublicKeyCheck() in the examples.
- Record that with no callback registered the host key is rejected
  with WS_PUBKEY_REJECTED_E.

Issue: F-6976
2026-08-10 13:53:08 -06:00
John Safranek 4bdc7e6c5c ssh.h: document the WS_CallbackUserAuth contract
- WOLFSSH_USERAUTH_SUCCESS is 0, the same value as WS_SUCCESS and the
  C "no error" idiom, so a bare "return 0", a forwarded WS_SUCCESS, or
  a fall-through default of 0 silently authenticates the client.
- Spell out that the callback must fail closed: return
  WOLFSSH_USERAUTH_FAILURE for any authType or code path it does not
  explicitly handle.
- Note that for WOLFSSH_USERAUTH_PUBLICKEY the library verifies the
  signature but not the key's authorization, so the callback has to
  check the offered key against the user's authorized keys.

Issue: F-6815
2026-08-10 13:53:08 -06:00
John Safranek 4f827ca4a9 Reject client conn messages before key exchange
- IsMessageAllowedClient() gated the post-userauth rejection on
  connectState >= CONNECT_KEYED, so every state below it allowed
  msgid 80 and above.
- A client in the pre-key-exchange DoReceive() loops accepted an
  unencrypted CHANNEL_OPEN, created the channel and replied with
  CHANNEL_OPEN_CONF.
- Add a state sweep over the connection-protocol range and a full
  DoReceive() of a plaintext CHANNEL_OPEN from a pre-auth state.

Issue: F-7628
2026-08-10 12:49:49 -07:00
Ruby Martin ab8058d7cd check return value of WFTELL() 2026-08-10 10:19:45 -07:00
Ruby Martin 97bbe42263 Add WFSEEK return value checks where previously discarded 2026-08-10 10:19:45 -07:00
Ruby Martin 2a30f48772 Update WFSEEK call sites that may misinterpret return value in Harmony/Nucleus builds 2026-08-10 10:19:45 -07:00
Ruby Martin bf5a8015e2 Define WFSEEK_SUCCESS() for instances where WFSEEK() returns non-zero success case 2026-08-10 10:19:45 -07:00
John Safranek e52fbd1f2c io: clean up Harmony send size clamp
- read TCPIP_TCP_PutIsReady() before comparing, and cast so the
  clamp is not a signed/unsigned comparison
- no behaviour change, the API returns uint16_t

Issue: F-7509
2026-08-10 10:31:07 -06:00
John Safranek 7e56f10b81 auth: free OpenSSH-certificate user keys
- cover the ID_OSSH_CERT_* key IDs in wolfSSH_KEY_clean
- zeroize the key signature struct before freeing it
- add a unit test for the RSA OpenSSH-certificate ID

Issue: F-7519
2026-08-10 10:31:07 -06:00
John Safranek a62534936f client: handle select() errors in readPeer
- store select()'s result in an int so an error is not read
  as a large positive count
- retry on EINTR, bail out on any other error
- re-arm the descriptor sets on every pass

Issue: F-7508
2026-08-10 10:31:07 -06:00
John Safranek c61c7a04dd client: fix keyboard-interactive responses
- zero the response arrays and stop filling after the first
  failed read, tracking only the slots populated
- release the previous round's responses on each INFO_REQUEST
- add auth.test coverage for EOF stdin and a second round

Issue: F-7515, F-7516
2026-08-10 10:31:07 -06:00
John Safranek 457ac40255 certs: reject an empty RFC 6187 cert chain
- fail ParseCertChain when the peer sends a zero cert count
- only set isCert when a leaf was actually parsed
- add a ParseLeafCert test hook and zero-count unit test

Issue: F-7517
2026-08-10 10:31:07 -06:00
John Safranek 319180beff ssh: match channel request types exactly
- add ChannelRequestIs() comparing the type length as well
- use it for all nine handled request types, so truncated,
  empty and NUL-padded types are rejected
- cover "sh", "sub", empty and "shell\0AAAA" in unit tests

Issue: F-7217
2026-08-10 10:31:07 -06:00
John Safranek 7c4b1d3549 kex: keep GenerateKey hash error in loop
- gate the multi-block loop on ret so the first wc_HashFinal
  result is not discarded
- add a SHA-256 two-block key expansion known-answer test

Issue: F-7507
2026-08-10 10:31:07 -06:00
John Safranek 28185e4d90 scp: reject NULL message in SetScpErrorMsg
- check message for NULL alongside ssh
- drop the always-true valueSz guard
- cover both NULL arguments in test_wolfSSH_SCP_CB

Issue: F-7510
2026-08-10 10:31:07 -06:00
Yosuke Shimizu c2d169872e Add certificate loading APIs with content-based format detection 2026-08-05 23:02:51 -07:00
Emma Stensland 492e8cd65d Mitigate user enumeration timing oracle using dummy hash cache 2026-08-05 12:26:46 -07:00
John Safranek 48f1bd02ec wolfsftp: clear the handle size when the remote open fails
- handleSz is the handle buffer size going into wolfSSH_SFTP_Open(), so
  a failed open left it non-zero and STATE_PUT_CLOSE_REMOTE closed a
  zeroed handle for a file that was never opened.
- The stray close overwrote ret and ssh->error, hiding the real cause.
2026-08-05 13:57:57 -05:00
John Safranek 109e787759 wolfsshd: drop dead dCert NULL check
Without WOLFSSH_SMALL_STACK dCert is the address of a stack variable, so
the NULL check could never fire. Keep the check under the small stack
build where the WMALLOC can actually fail.

Issue: CID-573006
2026-08-05 13:57:57 -05:00
John Safranek 960282ae47 wolfsshd: retry the final shell output flush
The drain after waitpid ignored the send return, so on a non-blocking
socket the tail of a command's output was dropped on a full window, a
rekey or a would block. Retry a bounded number of times and log when
the data still can not be sent.

Issue: CID-572907
2026-08-05 13:57:57 -05:00
John Safranek f4659eac86 wolfsshd: check fcntl results in the pipe drain
The leftover-data drain after waitpid ignored both fcntl calls. Check
the get and the set, and skip the drain read for a pipe that could not
be made non-blocking so the read cannot hang the connection process.

Issue: CID-572931
2026-08-05 13:57:57 -05:00
John Safranek 0ac4a3d771 examples/client: drop dead select_ret tests in NonBlockSSH_connect
The loop condition already guarantees a want-read or want-write error,
so the select_ret arms of the retry test and the else chain could never
run. Retry unconditionally; tcp_select still throttles the loop. Same
change applied to the copy in apps/wolfssh/wolfssh.c.

Issue: CID-572884
2026-08-05 13:57:57 -05:00
John Safranek afb4d70c5f apps/wolfssh, examples/client: retry readInput sends over a rekey
Both loop exits in readInput() returned early, leaving the per-thread
ECC cache cleanup after the loop unreachable. Break out of the loop
instead.

wolfSSH_stream_send() reports a rekey in progress by returning
WS_FATAL_ERROR with the ssh error set to WS_REKEYING, so testing the
return value against WS_REKEYING never matches. Read the code with
wolfSSH_get_error() and resend the same buffer once the rekey
finishes, in both the app and the example client. Looping back to
read() instead would drop the input already taken from stdin.

Issue: CID-572833
2026-08-05 13:57:57 -05:00
John Safranek f6ff8dc028 apps/wolfssh: wire up the -a agent option
The useAgent flag was never set, so both agent setup blocks in
wolfSSH_Client were dead code. Add the -a option to the parser and
carry it through the config struct, matching examples/client/client.c.

Issue: CID-572857
2026-08-05 13:57:57 -05:00