Generate exact-hash SDK source overrides without modifying dependencies. Harden SSH allocation and algorithm policy, tighten web authentication cleanup, and add focused host contract tests and documentation.
Pinned wolfSSH authentication control-flow contract
Run from the repository root:
CCACHE_DISABLE=1 python3 tests/wolfssh_auth_contract/run.py
Requires Python 3, a host C compiler (CC, default cc), installed managed
wolfSSH, and an existing firmware compilation database/toolchain. No packages
are downloaded and no firmware build or device commands run. Generated C and
the executable live in a temporary directory and are removed on exit. Compile,
preprocess and execution subprocesses have 30/30/10-second limits.
The runner prefers the sole .pio/build/*/compile_commands.json, otherwise the
root database. Select another existing database with --compile-commands PATH.
It requires the actual generated wolfSSH internal.c compilation input to equal
tools/security_overrides.py's rendering of the pinned original, preprocesses
that compile command (-E -dM), and checks this reviewed profile:
LIBWOLFSSH_VERSION_HEX == 0x01004020(1.4.20).- RSA disabled; ECDSA and Ed25519 not disabled.
- Certificates,
noneauthentication andNO_FAILURE_ON_REJECTEDnot defined.
For hosts without the ESP compiler/database, explicitly use --host-only.
This prints a SKIP for production feature verification; it still checks the
source/version/pin and executes the rendered host contract with the reviewed
feature profile. A stale compilation database is not proof of the next firmware build's
configuration.
What executes
run.py checks the exact application wolfSSH pin, installed version header and
reviewed SHA-256 of managed_components/wolfssl__wolfssh/src/internal.c:
81ff1f9166708abd5c2911e9fe57c0aee01c88b5d3f68c909ee8a856d37f36a9
Any same-version source change fails before compilation. Re-audit before updating this hash; do not automatically bless a dependency update.
The runner extracts actual overridden production function definitions by balancing braces after masking comments/string literals. Extraction does not rewrite their bodies; the separately verified build overlay does:
GetBoolean,GetUint32,GetSize,GetStringRefDoUserAuthRequestPassword,DoUserAuthRequestPublicKey,DoUserAuthRequestSendUserAuthKeyboardRequest,GetAllowedAuthSendChannelData
Callback data structures, auth result constants and method masks are extracted
from the installed public header. contract.c supplies small session/context
models, name/algorithm lookup, crypto and packet-output doubles. Binary request
fixtures execute the extracted parsers; ordered event traces assert callback,
hashing/signature and response order, rather than inspecting source substrings.
The 35 baseline cases cover (with the stricter malformed-password contract):
- Ed25519 and ECDSA: signed authorization rejection (
INVALID_PUBLICKEY,FAILURE,REJECTED,INVALID_USER,INVALID_AUTHTYPE) never hashes, verifies or calls the result callback. - Both unsigned probe outcomes: no signature work/result callback; an accepted probe sends PK_OK but does not complete authentication.
- Bad signatures, good signatures, success-result veto, ignored failure-result
callback return, and auth
WOULD_BLOCK. - Password success/failure, rejected password change, and rejection before the callback for a truncated new-password-length field. No password result callback.
- Disabled
none, unknown methods/key algorithms and truncated signed framing. - Direct keyboard-interactive dispatch invokes a registered non-NULL rejecting prompt callback, returns error and purges without preparing/building/sending a prompt. The actual library still writes the message-ID byte into its existing output buffer on this path; the test models that buffer and checks this detail.
- The actual advertised-method builder excludes keyboard despite the registered keyboard callback, because the allowed-types callback overrides the defaults.
- Actual
SendChannelDatacopies the bounded consumed prefix before returning a positive count, both on send success andWS_WANT_WRITE. Wiping that caller prefix leaves the library copy intact. A blocked flush of earlier data returns a negative code without consuming new data.
A further 100 generated-parser cases test short/missing flags and lengths,
truncated/oversized/UINT32_MAX password and replacement-password lengths,
checked initial offsets and canaries, no callback on malformed fields, preserved
username/service/method prefixes, and suffix wiping before response emission.
They include success, invalid/backend/rejected outcomes, password changes, no
callback, callback-modified credential pointers/lengths, and pending retry.
WS_AUTH_PENDING deliberately preserves bytes; the project's synchronous
callbacks do not use it. This is not an unconditional async secret-wipe promise.
Limits / ownership
This is a library parser/control-flow regression, not application callback integration coverage. Its rejecting keyboard callback models the parent's registration and return policy; it does not prove production registration, admission counters, awaiting-result state, principal promotion, or admin wiping. Those belong to the separate application unit suite.
Crypto helpers are instrumented doubles; algorithm name lookup is limited to fixture names. Packet construction/network send, hashing and session internals are modeled. This does not validate cryptographic correctness, encrypted packet decoding, real sockets, asynchronous re-entry, complete malformed-input safety, allocation failure, memory erasure throughout wolfSSH, or device behavior. The send test proves only the extracted copy/consumed control flow with successful packet preparation/bundling and the specified send outcomes—not the entire admin transmit loop or TLS/SSH buffer lifecycle.
All Phase9 hardware validation remains deferred to the combined phase.