Harden wolfSSL and wolfSSH validation
Enable validated ECC imports and X25519 all-zero rejection through PUBLIC build policy. Tighten wolfSSH parser bounds, overflow handling, and signature framing with guard-page and crypto vector contracts.
This commit is contained in:
@@ -1,97 +1,114 @@
|
||||
# Bounded CVE-2025-12888 mitigation
|
||||
# Bounded wolf crypto compile policy
|
||||
|
||||
Scope: project-owned build configuration only, retaining wolfSSL 5.8.2~1 and
|
||||
wolfSSH 1.4.20 pins and unmodified managed sources. This is not an upstream
|
||||
upgrade, blanket security clearance, or mitigation of other listed advisories.
|
||||
Project-owned configuration for pinned wolfSSL 5.8.2~1 / wolfSSH 1.4.20;
|
||||
no installed vendor edits, dependency upgrades, generated override edits or
|
||||
blanket security clearance. See the [key-validation review](../../docs/ssh_key_validation_review.md)
|
||||
for exact source hashes, applicability, upstream guidance and remaining gaps.
|
||||
|
||||
## Upstream and installed evidence
|
||||
## Policy
|
||||
|
||||
On 2026-09-15, inspected official
|
||||
[PR9275 files](https://api.github.com/repos/wolfSSL/wolfssl/pulls/9275/files)
|
||||
([PR](https://github.com/wolfSSL/wolfssl/pull/9275), head reported by the files
|
||||
API: `c161cbd9f3fa1247382bb5b6269c7379222cabf5`). Its `settings.h` patch
|
||||
selects `CURVE25519_SMALL`, `ED25519_SMALL`, `CURVE448_SMALL`, and `ED448_SMALL`
|
||||
under `__xtensa__`: Xtensa compilers have generated non-constant-time assembly
|
||||
from the fast C implementation; upstream says the small implementation is not
|
||||
known to have those issues. This is upstream mitigation guidance, not proof of
|
||||
constant-time execution on our compiler/device.
|
||||
|
||||
Installed `include/user_settings.h` enables X25519 and Ed25519. Installed
|
||||
`wolfssl/wolfcrypt/settings.h` automatically enables X25519 blinding only for
|
||||
non-small math; `wolfcrypt/src/curve25519.c` rejects blinding with small math.
|
||||
`fe_low_mem.c` and `ge_low_mem.c` provide the small implementations and already
|
||||
have entries in the production compilation database. Small flags change public
|
||||
key layout/signatures: never mix old library objects with newly compiled callers.
|
||||
|
||||
Root `CMakeLists.txt` sets both small flags before component processing, alongside
|
||||
the existing global crypto controls. `cmake/wolf_crypto_policy.cmake` attaches a
|
||||
forced-include resolved-settings guard to wolfSSL with PUBLIC propagation to its
|
||||
consumers, including wolfSSH and application code. The guard rejects missing
|
||||
algorithms/small flags, incompatible blinding, and future 448 enablement pending
|
||||
explicit review. No blinding-disable macro or vendor source patch is needed.
|
||||
RNG callback and software AES/SHA settings remain unchanged.
|
||||
- Existing root definitions `CURVE25519_SMALL` / `ED25519_SMALL` follow
|
||||
[PR9275](https://github.com/wolfSSL/wolfssl/pull/9275)'s Xtensa mitigation.
|
||||
Small math is incompatible with this version's X25519 blinding; do not mix
|
||||
ABI-sensitive library and consumer settings. Curve448/Ed448 require review.
|
||||
- `cmake/wolf_crypto_policy.cmake` now PUBLIC-defines
|
||||
`WOLFSSL_VALIDATE_ECC_IMPORT` and `WOLFSSL_ECDHX_SHARED_NOT_ZERO`, enabling
|
||||
existing upstream P256 import and X25519 result checks. The root already
|
||||
includes this module; no root edit is needed.
|
||||
- The PUBLIC forced-include guard checks resolved settings and rejects missing
|
||||
requirements and known ECC validator-disabling/hardware-stub configurations.
|
||||
Existing RNG callback and software AES/SHA controls are unchanged.
|
||||
|
||||
## Commands
|
||||
|
||||
From the repository root, after the parent regenerates/builds the firmware:
|
||||
|
||||
```sh
|
||||
# Offline host subset; no target compiler/database required:
|
||||
python3 tests/wolf_crypto_policy/run.py --host-only
|
||||
|
||||
# Explicit candidate replay before production reconfiguration:
|
||||
python3 tests/wolf_crypto_policy/run.py --candidate
|
||||
|
||||
# Strict production evidence after the parent reconfigures/builds:
|
||||
python3 tests/wolf_crypto_policy/run.py
|
||||
```
|
||||
|
||||
Optional explicit database:
|
||||
Optional database argument:
|
||||
|
||||
```sh
|
||||
python3 tests/wolf_crypto_policy/run.py --compile-commands .pio/build/esp32-s3-devkitc-1-n16r8/compile_commands.json
|
||||
```
|
||||
|
||||
Strict mode requires the actual compile commands to carry the policy guard and
|
||||
uses their actual compiler, include paths and definitions without adding small
|
||||
flags. Missing/ambiguous entries, absent policy, wrong architecture, incompatible
|
||||
macros, compiler errors and failed vectors fail the test. It preprocesses and
|
||||
syntax-checks ten translation units: Curve25519, Ed25519, fast and small field/group
|
||||
math, wolfSSH `ssh.c`, generated wolfSSH `internal.c`, application transport and
|
||||
security. Two additional actual-settings checks remove each small flag and must
|
||||
fail. It does not modify generated sources or compile databases.
|
||||
Candidate mode injects all four policy definitions and the guard into saved
|
||||
commands. It is **not production configuration/build evidence**. Strict mode
|
||||
injects nothing, and must fail with stale commands lacking the new flags.
|
||||
No mode runs PlatformIO, regenerates overrides or communicates with a device.
|
||||
|
||||
Before the parent reconfigures, explicitly test the candidate using old commands:
|
||||
## Coverage
|
||||
|
||||
```sh
|
||||
python3 tests/wolf_crypto_policy/run.py --candidate
|
||||
```
|
||||
All modes:
|
||||
|
||||
This injects the two small flags and the guard and labels its output **CANDIDATE
|
||||
replay**, not production configuration evidence. It does not run CMake/PlatformIO.
|
||||
Host-only subset:
|
||||
- 20 fail-closed guard matrix cases.
|
||||
- A temporary CMake project includes the actual production policy module and
|
||||
verifies PUBLIC definitions/guard across wolf library → SSH → app targets.
|
||||
This is a stand-in graph, not an ESP-IDF build.
|
||||
- Compile installed small implementations and run RFC7748 X25519 and RFC8032
|
||||
Ed25519 vectors plus corrupted-signature rejection. Check two nontrivial
|
||||
low-order X25519 points that pass the vendor public precheck but must fail
|
||||
shared-secret calculation without copying output; also reject zero/one inputs.
|
||||
- Compile installed TFM ECC, ASN template, signature and supporting primitives.
|
||||
Test explicit/inferred P256 import of valid G and rejection of off-curve,
|
||||
infinity, out-of-range, truncated and wrong-tag inputs; valid ECDH; raw and
|
||||
DER-wrapper ECDSA valid/invalid verification; valid SEC1 private DER decoding
|
||||
without a pre-attached RNG and rejection of an invalid embedded public point.
|
||||
Test scalar/nonce values are deliberately public test values, never real keys.
|
||||
|
||||
```sh
|
||||
python3 tests/wolf_crypto_policy/run.py --host-only
|
||||
```
|
||||
Target modes additionally:
|
||||
|
||||
All modes run eight guard matrix cases and compile the installed vendor small
|
||||
implementations into a temporary host executable: RFC7748 section 6.1 X25519
|
||||
shared secret, RFC8032 section 7.1 test 1 Ed25519 empty-message verification, and
|
||||
rejection of a corrupted signature. Host settings are deliberately minimal,
|
||||
with streaming verification enabled and unused functions garbage-collected;
|
||||
they are not the ESP-IDF runtime/entropy/hardware configuration. No synthetic
|
||||
implementation substitutes for the tested arithmetic. Requirements: Python 3,
|
||||
`cc`/linker, installed managed component; target checks also require the existing
|
||||
Xtensa toolchain, generated headers and compile database. Commands are bounded;
|
||||
temporary outputs are removed automatically.
|
||||
- Pin original wolfSSH `internal.c` and wolfCrypt `ecc.c`, `curve25519.c`,
|
||||
`signature.c`; locate the actual generated wolfSSH compile input and compare
|
||||
seven complete audited crypto/auth/hash function bodies: five must remain
|
||||
identical, while ECC/Ed25519 authentication must match independently specified
|
||||
exact label/framing deltas reconstructed from the hash-pinned original, with
|
||||
exact anchor counts. Expectations are not imported from the generator. Any
|
||||
additional change requires re-audit, not repinning or skipping a body. This
|
||||
does not validate the entire override generator. Generated hash is printed.
|
||||
- Replay actual Xtensa compiler/includes for macro and syntax checks of twelve
|
||||
translation units: ECC, signature wrapper, Curve25519, Ed25519, fast/small
|
||||
field/group math, wolfSSH `ssh.c`, generated `internal.c`, application SSH
|
||||
transport and security. Confirm internal `HAVE_ECC_CHECK_PUBKEY_ORDER` in ECC.
|
||||
- Four negative actual-settings tests remove one policy flag at a time.
|
||||
|
||||
## Validation and remaining gates
|
||||
Requirements: Python 3, CMake, host `cc`/linker, installed managed sources;
|
||||
target modes also require the existing Xtensa toolchain, generated headers and
|
||||
compilation database. Subprocesses have time bounds and temporary artifacts are
|
||||
removed. No replacement crypto implementation or crypto success double is used.
|
||||
|
||||
Implemented validation: candidate replay passed all ten macro/syntax checks,
|
||||
eight guard cases, two real-settings rejection cases, and the three host vector
|
||||
checks. Initial host harness compilation exposed a disabled SHA256 declaration
|
||||
dependency and omitted small-math source files; the harness was corrected to use
|
||||
the installed small source files explicitly.
|
||||
## Evidence and remaining gates — 2026-09-15
|
||||
|
||||
The parent must run the normal full build and then strict mode above. A build was
|
||||
explicitly not run for this task. Existing compile-database success alone would
|
||||
not prove the linked/flashed image matches it. No device operations were run.
|
||||
Still required: target SSH X25519 negotiation, Ed25519 authentication, rekey,
|
||||
combined service load, stack/heap reserves and handshake latency/deadline checks.
|
||||
Small implementations may reduce performance; no target timing, side-channel
|
||||
measurement, interoperability or resource claim is made. Host vectors are narrow
|
||||
correctness checks, not exhaustive cryptographic validation.
|
||||
Follow-up strict production run PASS without candidate injection, including all
|
||||
host tests (20 guard cases, three-target CMake propagation, real crypto and ASN
|
||||
vectors), seven complete source-body comparisons with reviewed exact parser
|
||||
deltas, twelve target macro/syntax checks and four negative target-settings
|
||||
cases. Earlier candidate and host-only runs also passed; the final ASN-decode
|
||||
cases passed in candidate and strict runs.
|
||||
Earlier development runs required correcting fixture settings/linkage; they
|
||||
are not additional production failures. Host settings retain TFM, timing
|
||||
resistance and small-stack allocation for ECC, but differ in word size,
|
||||
allocator, OS entropy and hardware/compiler configuration. No sanitizer,
|
||||
exhaustive fuzzing, allocation-failure injection or timing result is claimed.
|
||||
|
||||
The parent reports `pio run` PASS: 94,340 B linked RAM / 1,768,949 B flash.
|
||||
This agent did not run PlatformIO or devices; local strict checks validate the
|
||||
saved production compile profile, not a flashed image. Hardware tests remain
|
||||
necessary for both KEX algorithms, P256/Ed25519 authentication, host-key loading,
|
||||
rekey, malformed-key failure/cleanup, combined load, stack/heap reserves and
|
||||
handshake deadlines. Extra import validation has real CPU/allocation cost.
|
||||
|
||||
The parser owner separately fixed ECC/Ed25519 labels, ECC nested exact bounds
|
||||
and Ed25519 outer consumption in the generated input. Those changes are checked
|
||||
by this suite's exact source contract, not supplied by crypto compile flags.
|
||||
The parser suite was reviewed, not rerun in this follow-up; its crypto doubles
|
||||
establish parser gating, not real signature arithmetic. Broader ordering/state
|
||||
review, standalone ECC key-blob semantics outside application checks, generic
|
||||
wolfSSL digest/OID API hardening as applicable, and hardware gates remain open;
|
||||
see the review for evidence and limits.
|
||||
|
||||
Reference in New Issue
Block a user