Skip to content

OSCORE option parser accepts trailing garbage, kid flag without data, and duplicate OSCORE options #2051

Description

@afldl

While testing libcoap's OSCORE option handling, I found three parser compliance issues:

1. Trailing garbage bytes accepted

Input \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 (10 bytes):

  • Flags byte 0x00 is valid (no PIV, no kid_context, no kid)
  • But the remaining 9 bytes are trailing garbage that should be rejected
  • oscore_decode_option_value() returns success

2. Kid flag set without kid data

Input \x08 (1 byte):

  • Flags byte 0x08: kid flag = 1
  • But there are 0 bytes of kid data following
  • Parser returns kid=0 — an impossible state (flag says present, data says absent)
  • RFC 8613 §6.2: "If the 'kid' flag is 1, then the 'kid' value..." implies kid bytes MUST be present

3. Duplicate OSCORE options accepted

CoAP PDU with two OSCORE options (option 9 twice) — coap_pdu_parse() accepts without error. RFC 8613 §6.1: at most one OSCORE option per message.

Verified with harness h_libcoap_oscore_option_noasan:

10 zero bytes → L0=accept err=0 flags=0x00
0x08 alone   → L0=accept err=0 flags=0x08

Fix in src/oscore/oscore.c:

// After decoding, check for trailing bytes:
if (consumed < option_len) {
    return 0;  // reject trailing garbage
}
// Validate structural consistency:
if ((flags & OSCORE_KID_FLAG) && cose->key_id.length == 0) {
    return 0;  // kid flag set but no data
}

Found through differential fuzzing of CoAP implementations (PathDiff).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions