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:
@@ -117,6 +117,28 @@ def enum_containing(source, token):
|
||||
return matches[0] + "\n"
|
||||
|
||||
|
||||
def reviewed_order_function(name, original):
|
||||
"""Independent, exact allowlist; do not accept an arbitrary generator delta."""
|
||||
if name == 'SendExtInfo':
|
||||
return ('int SendExtInfo(WOLFSSH* ssh)\n{\n'
|
||||
' WOLFSSH_UNUSED(ssh);\n return WS_NOT_COMPILED;\n}\n')
|
||||
if name == 'SendKexInit':
|
||||
edits = (
|
||||
(' ssh->isKeying = 1;',
|
||||
' /* Set self is keying flag since we started sending the KEX init msg */\n'
|
||||
' ssh->isKeying |= WOLFSSH_SELF_IS_KEYING;'),
|
||||
(' if (ssh->ctx->side == WOLFSSH_ENDPOINT_CLIENT) {\n'
|
||||
' kexAlgoNamesPlus = ",ext-info-c";\n'
|
||||
' kexAlgoNamesPlusSz = (word32)WSTRLEN(kexAlgoNamesPlus);\n }\n\n', ''),
|
||||
(' if (ret == WS_SUCCESS)\n ret = wolfSSH_SendPacket(ssh);',
|
||||
' if (ret == WS_SUCCESS) {\n ret = wolfSSH_SendPacket(ssh);\n }'),
|
||||
)
|
||||
for old, new in edits:
|
||||
assert original.count(old) == 1, name
|
||||
original = original.replace(old, new)
|
||||
return original
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
databases = sorted((ROOT / ".pio/build").glob("*/compile_commands.json"))
|
||||
@@ -182,15 +204,23 @@ def main():
|
||||
|
||||
functions = ("NameToId", "IdToName", "AlgoListSz", "CopyNameList",
|
||||
"CopyNameListPlus", "BuildNameList", "SendKexInit", "SendExtInfo")
|
||||
actual = "\n".join(extract(sources["ssh.c"], "wolfSSH_CTX_SetAlgoList" + field)
|
||||
for field in FIELDS)
|
||||
ssh_entry = next(e for e in ENTRIES if e.name == 'wolfssh_ssh')
|
||||
_, generated_ssh = render_entry(ssh_entry, {'project': ROOT})
|
||||
actual = ''
|
||||
for field in FIELDS:
|
||||
name = 'wolfSSH_CTX_SetAlgoList' + field
|
||||
body = extract(generated_ssh.decode(), name)
|
||||
assert body == extract(sources['ssh.c'], name), name
|
||||
actual += body
|
||||
for name in functions:
|
||||
if extract(internal, name) != extract(sources["internal.c"], name):
|
||||
if extract(internal, name) != reviewed_order_function(name, extract(sources["internal.c"], name)):
|
||||
raise RuntimeError(f"Override changed reviewed protocol function: {name}")
|
||||
actual += "\n".join(extract(internal, name) for name in functions)
|
||||
# Preserve actual conditional enum values and feature-filtered name table.
|
||||
types = "\n".join(enum_containing(resolved, token) for token in
|
||||
("ID_NONE", "TYPE_KEX", "MSGID_KEXINIT", "WOLFSSH_ENDPOINT_SERVER"))
|
||||
assert macros['WOLFSSH_SELF_IS_KEYING'] == '0x02'
|
||||
types += '#define WOLFSSH_SELF_IS_KEYING 0x02\n'
|
||||
types += "typedef struct { byte id; byte type; const char *name; } NameIdPair;\n" + mapping
|
||||
assignments = []
|
||||
for field in FIELDS:
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "resolved.h"
|
||||
|
||||
#define WLOG(...) ((void)0)
|
||||
#define WOLFSSH_UNUSED(x) ((void)(x))
|
||||
#define INLINE inline
|
||||
#define WMEMCPY memcpy
|
||||
#define WSTRLEN strlen
|
||||
@@ -18,9 +19,7 @@
|
||||
#define LENGTH_SZ 4U
|
||||
#define BOOLEAN_SZ 1U
|
||||
#define COOKIE_SZ 16U
|
||||
#define WS_EXTINFO_EXTENSION_COUNT 1
|
||||
static const char cannedNoneNames[] = "none";
|
||||
static const char serverSigAlgsName[] = "server-sig-algs";
|
||||
|
||||
typedef struct { byte *kexInit; word32 kexInitSz; } HandshakeInfo;
|
||||
typedef struct {
|
||||
@@ -206,14 +205,13 @@ int main(void)
|
||||
assert(SendKexInit(ssh) == WS_SUCCESS);
|
||||
check_kex(ssh);
|
||||
assert(sends == 2 && allocations == 2 && frees == 1);
|
||||
assert(SendExtInfo(ssh) == WS_SUCCESS);
|
||||
size_t offset = 1, length = ssh->outputBuffer.length - 8U;
|
||||
const byte *p = packet + 8;
|
||||
assert(p[0] == MSGID_EXT_INFO);
|
||||
assert(take_u32(p, length, &offset) == 1);
|
||||
expect_name(p, length, &offset, "server-sig-algs");
|
||||
expect_name(p, length, &offset, "ssh-ed25519,ecdsa-sha2-nistp256");
|
||||
assert(offset == length);
|
||||
assert(ssh->isKeying == WOLFSSH_SELF_IS_KEYING);
|
||||
assert(SendExtInfo(ssh) == WS_NOT_COMPILED);
|
||||
assert(sends == 2);
|
||||
ctx.side = WOLFSSH_ENDPOINT_CLIENT;
|
||||
assert(SendKexInit(ssh) == WS_SUCCESS);
|
||||
check_kex(ssh); /* Client must not append ext-info-c either. */
|
||||
ctx.side = WOLFSSH_ENDPOINT_SERVER;
|
||||
/* No key and injected packet/allocation failures must not send a fallback. */
|
||||
unsigned before = sends;
|
||||
ctx.privateKeyCount = 0;
|
||||
@@ -234,6 +232,6 @@ int main(void)
|
||||
assert(purges == old_purges);
|
||||
check_kex(ssh);
|
||||
bounded_free(handshake.kexInit);
|
||||
puts("PASS: resolved vendor name/ID/type map, actual setters, initial/rekey KEXINIT both directions, server-sig-algs, bounded failure paths");
|
||||
puts("PASS: resolved vendor name/ID/type map, actual setters, initial/rekey KEXINIT both directions, no EXT_INFO negotiation, bounded failure paths");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user