Add restricted wolfSSH ordering fix

Apply hash-pinned generated edits for CVE-2025-14942 while keeping
wolfSSH 1.4.20 managed sources unchanged. Add the ABI header overlay,
provenance records, and real state-machine interoperability contracts.
This commit is contained in:
2026-09-16 14:04:34 +02:00
parent 4d3bb490c9
commit bea33e1c95
28 changed files with 4653 additions and 64 deletions
+46 -4
View File
@@ -11,6 +11,7 @@ from __future__ import annotations
import argparse
from dataclasses import dataclass
import hashlib
import json
import os
from pathlib import Path
import re
@@ -37,6 +38,7 @@ class Entry:
sha256: str
edits: tuple[Edit, ...]
target: str = "" # Explicit nested library; empty means IDF COMPONENT_LIB.
header: bool = False # PUBLIC overlay, never a translation unit.
MODIFICATION_NOTICE = """/* Modified by the ESP32_serial_swiss_army_knife project on 2026-09-15.
@@ -47,6 +49,15 @@ MODIFICATION_NOTICE = """/* Modified by the ESP32_serial_swiss_army_knife projec
"""
# Exact, reviewed consolidated delta; upstream mail patches are provenance only.
# No network, patch utility, fuzz, or managed-component mutation at configure time.
WOLFSSH_ORDER_DIR = Path(__file__).resolve().parent / "wolfssh_order"
WOLFSSH_ORDER_PLAN = json.loads((WOLFSSH_ORDER_DIR / "delta.json").read_text())
WOLFSSH_ORDER_EDITS = {
path: tuple(Edit(**edit) for edit in item["edits"])
for path, item in WOLFSSH_ORDER_PLAN.items()
}
WIPE = """/* Retired secret-bearing storage must not survive allocator reuse. */
static void security_override_wipe(void *buffer, size_t length)
{
@@ -427,7 +438,7 @@ ENTRIES = (
), target="mbedx509"),
Entry("wolfssh_internal", "wolfssl__wolfssh", "project",
"managed_components/wolfssl__wolfssh/src/internal.c",
"81ff1f9166708abd5c2911e9fe57c0aee01c88b5d3f68c909ee8a856d37f36a9", WOLFSSH_PARSER_EDITS + (
"81ff1f9166708abd5c2911e9fe57c0aee01c88b5d3f68c909ee8a856d37f36a9", WOLFSSH_ORDER_EDITS["src/internal.c"] + WOLFSSH_PARSER_EDITS + (
Edit(""" WS_UserAuthData_Password* pw = NULL;
int ret = WS_SUCCESS;
""", """ WS_UserAuthData_Password* pw = NULL;
@@ -582,6 +593,18 @@ ENTRIES = (
)
ENTRIES += (
Entry("wolfssh_ssh", "wolfssl__wolfssh", "project",
"managed_components/wolfssl__wolfssh/src/ssh.c",
"a4f479ff87eea0980ec1ebdf2c7dd090da473780181b695a56799cb9611f4366",
WOLFSSH_ORDER_EDITS["src/ssh.c"]),
Entry("wolfssh_internal_header", "wolfssl__wolfssh", "project",
"managed_components/wolfssl__wolfssh/wolfssh/internal.h",
"8e417149a68f8a6c0506957adf014b3e6c1727a723536826ce5fb0c9e1f1aba3",
WOLFSSH_ORDER_EDITS["wolfssh/internal.h"], header=True),
)
def apply_edits(text: str, edits: tuple[Edit, ...]) -> str:
for index, edit in enumerate(edits, 1):
count = text.count(edit.old) if edit.old else 0
@@ -607,6 +630,11 @@ def render_entry(entry: Entry, roots: dict[str, Path]) -> tuple[Path, bytes]:
if entry.target and (entry.component != "mbedtls" or entry.target not in
{"mbedtls", "mbedx509", "mbedcrypto"}):
raise OverrideError("invalid nested target selection")
if entry.header and (entry.name != "wolfssh_internal_header" or
entry.component != "wolfssl__wolfssh" or entry.target or
entry.root != "project" or entry.source !=
"managed_components/wolfssl__wolfssh/wolfssh/internal.h"):
raise OverrideError("unaudited header overlay")
root = roots[entry.root].resolve()
source = (root / entry.source).resolve()
if not source.is_relative_to(root):
@@ -615,7 +643,18 @@ def render_entry(entry: Entry, roots: dict[str, Path]) -> tuple[Path, bytes]:
actual = hashlib.sha256(raw).hexdigest()
if actual != entry.sha256:
raise OverrideError(f"{entry.name}: SHA256 mismatch for {source}: expected {entry.sha256}, got {actual}; reaudit, do not repin blindly")
return source, (MODIFICATION_NOTICE + apply_edits(raw.decode("utf-8"), entry.edits)).encode("utf-8")
notice = MODIFICATION_NOTICE
if entry.component == "wolfssl__wolfssh":
notice += ("/* Ordering profile modified 2026-09-16: PR793/819/840/855/921\n"
" * plus project restricted no-EXT_INFO correction. Provenance and\n"
" * limitations: tools/wolfssh_order/README.md and delta.json.\n"
" */\n")
if entry.header:
notice += ("#if defined(_WOLFSSH_INTERNAL_H_) && \\\n"
" (!defined(SAK_WOLFSSH_ORDER_ABI) || SAK_WOLFSSH_ORDER_ABI != 20260916)\n"
'#error "Security override: stale wolfSSH internal.h included before overlay"\n'
"#endif\n#define SAK_WOLFSSH_ORDER_ABI 20260916\n")
return source, (notice + apply_edits(raw.decode("utf-8"), entry.edits)).encode("utf-8")
def write_if_changed(path: Path, data: bytes) -> bool:
@@ -659,10 +698,13 @@ def generate(idf: Path, project: Path, binary: Path, entries: tuple[Entry, ...]
if source in seen:
raise OverrideError(f"ambiguous duplicate source: {source}")
seen.add(source)
target = output / entry.name / source.name
target = (output / "wolfssh_include" / "wolfssh" / source.name
if entry.header else output / entry.name / source.name)
rendered.append((entry, source, target, data))
lines = ["# Generated by tools/security_overrides.py; do not edit.",
"set(SAK_SECURITY_OVERRIDE_IDS " + " ".join(names) + ")",
"set(SAK_SECURITY_OVERRIDE_IDS " + " ".join(e.name for e in entries if not e.header) + ")",
"set(SAK_SECURITY_HEADER_IDS " + " ".join(e.name for e in entries if e.header) + ")",
"set(SAK_SECURITY_WOLFSSH_INCLUDE " + cmake_quote(str(output / "wolfssh_include")) + ")",
"set(SAK_SECURITY_VERSION_HEADER " + cmake_quote(str(version)) + ")"]
for entry, source, target, _ in rendered:
for key, value in (("COMPONENT", entry.component), ("TARGET", entry.target), ("ORIGINAL", str(source)),