Skip to content

Validate packet inputs and fail closed on malformed responses#263

Merged
Avi0n merged 1 commit into
Avi0n:devfrom
robekl:fix-packetbuilder-validation
Mar 25, 2026
Merged

Validate packet inputs and fail closed on malformed responses#263
Avi0n merged 1 commit into
Avi0n:devfrom
robekl:fix-packetbuilder-validation

Conversation

@robekl
Copy link
Copy Markdown
Contributor

@robekl robekl commented Mar 21, 2026

Summary

  • clamp PacketBuilder.sendRawData to current firmware path and payload limits
  • keep public-key command packets fixed-width for hasConnection, getContactByKey, and getAdvertPath
  • reject invalid public API inputs before sending for full-key request APIs and setPathHashMode
  • fail closed on malformed battery, contact, advert-path, device-info, and signed contact-message responses
  • add regression coverage in existing upstream test files only

Rationale

This change tightens validation at the correct protocol boundaries.

At the low-level packet-construction layer, callers should not be able to build malformed command frames that firmware will reject or misinterpret. That is why the builder now enforces the current raw-data limits and always emits fixed-width public-key fields for commands whose wire format requires 32 bytes.

At the public session API layer, methods that already document a full 32-byte public key now reject invalid input up front with MeshCoreError.invalidInput instead of silently padding or truncating user input and sending a request anyway. setPathHashMode(_:) similarly rejects reserved mode values before sending.

On the receive side, malformed responses should fail closed rather than being partially parsed into invented or defaulted state. This PR makes that explicit for:

  • partial extended battery payloads
  • reserved path-length encodings in contact and advert-path responses
  • truncated v10 device-info payloads missing required versioned fields
  • truncated signed contact-message payloads

Firmware Validation

I validated these client-side constraints against current meshcore firmware main behavior:

  • MAX_PATH_SIZE is 64 and MAX_PACKET_PAYLOAD is 184 in src/MeshCore.h
  • docs/packet_format.md documents path as up to 64 bytes and payload as up to 184 bytes
  • docs/packet_format.md and src/Packet.cpp treat path-length mode 0b11 / 3 as reserved or unsupported
  • firmware command and packet structures use fixed-width PUB_KEY_SIZE == 32 byte public-key fields

That means the builder clamping and fixed-width encoding are matching the current firmware contract, not inventing a client-only policy.

Why these layers

  • PacketBuilder is the shared construction boundary for protocol-shaped packets
  • MeshCoreSession is the right place for caller-facing input validation and clean errors
  • PacketParser / Parsers are the right place to reject malformed incoming wire data

That split avoids pushing protocol-specific validation into the transport or send layer while still giving higher-level callers better errors.

Validation

  • swift test --package-path MeshCore

Result:

  • 280 tests passed

Test coverage added

  • builder regression tests for raw-data clamping, fixed-width public-key encoding, and path-hash-mode clamping
  • session tests that invalid short-key inputs and reserved path-hash-mode values are rejected before any send occurs
  • parser tests for malformed battery, contact, advert-path, device-info, and signed contact-message payloads

@Avi0n
Copy link
Copy Markdown
Owner

Avi0n commented Mar 25, 2026

Thank you!

@Avi0n Avi0n merged commit 1c315b9 into Avi0n:dev Mar 25, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants