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).
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):oscore_decode_option_value()returns success2. Kid flag set without kid data
Input
\x08(1 byte):kid=0— an impossible state (flag says present, data says absent)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:Fix in
src/oscore/oscore.c:Found through differential fuzzing of CoAP implementations (PathDiff).