IETF CoAP RFC 7252 + RFC 7641 — Spec Coverage
RFC 7252: The Constrained Application Protocol — IETF, June 2014 →
RFC 7641: Observing Resources in CoAP — IETF, September 2015 →
Context: CoAP is a RESTful spec for constrained devices. ZeroDDS
implements it in crates/coap-bridge/: the wire codec (Section 3, 5.10,
RFC 7641 §2) as a no_std+alloc library, plus reliability, block-wise
transfer (RFC 7959), observe, a DTLS transport (feature dtls), OSCORE and
the daemon.
Implementation:
crates/coap-bridge/· docs.rs — codec, transport building blocks and the daemonzerodds-coap-bridged.
RFC 7252 §1 Introduction
§1.1 Features
Spec: §1.1, p. 5 (RFC) — REST model, UDP-bound, multicast support, DTLS security, asynchronous messaging.
Repo: crates/coap-bridge/src/lib.rs crate doc.
Tests: REST methods + response classes:
crates/coap-bridge/src/message.rs::tests::well_known_codes_match_spec_values;
asynchronous messaging (CON/NON/ACK/RST):
crates/coap-bridge/src/message.rs::tests::message_type_round_trips_via_bits;
multicast support:
crates/coap-bridge/src/multicast.rs::tests::well_known_addresses_match_spec;
DTLS security:
crates/coap-bridge/src/dtls.rs::tests::psk_is_secure;
UDP-bound (default ports 5683/5684):
crates/coap-bridge/src/uri.rs::tests::default_port_returns_5684_for_coaps.
Status: done — overview; multicast and DTLS are items of their own (§8, §9, §11).
§1.2 Terminology
Spec: §1.2, p. 6-9 — endpoint, sender, recipient, token, origin server, cacheable, resource, etc.
Repo: —
Tests: —
Status: n/a (informative) — glossary; a semantic reference point
without a code mapping.
RFC 7252 §2 Constrained Application Protocol
§2.1 Messaging model
Spec: §2.1, p. 11 — CON/NON/ACK/RST.
Repo: crates/coap-bridge/src/message.rs::MessageType.
Tests: message::tests::message_type_round_trips_via_bits.
Status: done
§2.2 Request/response model
Spec: §2.2, p. 12 — method codes + response codes.
Repo: crates/coap-bridge/src/message.rs::CoapCode with the constants
GET/POST/PUT/DELETE/CREATED/DELETED/VALID/CHANGED/CONTENT/BAD_REQUEST/NOT_FOUND/INTERNAL_SERVER_ERROR.
Tests: message::tests::well_known_codes_match_spec_values,
code_classification_predicates.
Status: done
§2.3 Intermediaries and caching
Spec: §2.3, p. 15 — forward proxies, caches.
Repo: crates/coap-bridge/src/caching_proxy.rs::{CoapCache, CacheLookup, ProxyConfig, ProxyMode} — a cache layer with freshness tracking +
stale/revalidate path; proxy configuration with forward/reverse mode +
hop-count cap (spec §5.7.1 loop protection).
Tests: crates/coap-bridge/src/caching_proxy.rs::tests::{empty_cache_returns_miss, store_then_fresh_lookup, stale_with_etag_yields_validation_path, stale_without_etag_yields_miss, cap_evicts_oldest, evict_expired_without_etag_keeps_revalidatable, proxy_config_default_is_forward_coap_to_coap}.
Status: done — caching + forward-proxy configuration live.
§2.4 Resource discovery
Spec: §2.4, p. 15 — .well-known/core (RFC 6690).
Repo: crates/coap-bridge/src/core_link.rs::{CoreLink, encode_links, decode_links}.
Tests: crates/coap-bridge/src/core_link.rs::tests::{encode_simple_link_format, encode_multiple_links_comma_separated, decode_round_trip_with_attrs, decode_handles_numeric_attr, decode_handles_quoted_string_with_comma, decode_rejects_uri_without_brackets, decode_attr_without_value_yields_empty, encode_escapes_inner_quotes}.
Status: done
RFC 7252 §3 Message format
§3 Header format (Ver/T/TKL/Code/MID)
Spec: §3, p. 16 — a 4-byte fixed header. Version MUST be 1 (01 binary),
TKL 0..=8 (9-15 reserved).
Repo: crates/coap-bridge/src/codec.rs::encode/decode sets Version=1 on
encode and rejects other versions on decode.
Tests: codec::tests::encodes_minimum_get_request_to_4_byte_header,
unsupported_version_decode_fails,
reserved_token_length_9_through_15_decode_fails,
token_length_above_8_is_rejected_on_encode.
Status: done
§3 Token
Spec: §3, p. 16 — a token 0..=8 bytes after the header.
Repo: crates/coap-bridge/src/message.rs::CoapMessage::token.
Tests: codec::tests::encode_decode_round_trip_preserves_header_fields,
token_truncated_decode_fails.
Status: done
§3 Payload marker
Spec: §3, p. 16-17 — 0xFF marks the start of the payload. “The presence
of a marker followed by a zero-length payload MUST be processed as a message
format error.”
Repo: crates/coap-bridge/src/codec.rs (encode + decode).
Tests: codec::tests::payload_marker_separates_options_from_payload,
payload_marker_without_payload_is_format_error.
Status: done
§3.1 Option format (delta encoding)
Spec: §3.1, p. 17-19 — a 4-bit delta nibble + a 4-bit length nibble + extended forms (13/14) + reserved (15). Options “MUST appear in order of their Option Numbers”.
Repo: crates/coap-bridge/src/codec.rs::encode_extended/decode_extended.
Encode sorts options before the delta computation.
Tests: codec::tests::single_short_option_encodes_in_one_byte_header,
option_delta_extended_13_uses_one_extra_byte,
option_delta_extended_14_uses_two_extra_bytes,
option_length_extended_13_uses_one_extra_byte,
delta_encoding_sums_across_multiple_options,
options_are_sorted_on_encode.
Status: done
§3.2 Option value formats
Spec: §3.2, p. 19-20 — empty, opaque, uint, string. uint “without
leading zero bytes”; “MUST be prepared to process values with leading zero
bytes”.
Repo: crates/coap-bridge/src/option.rs::OptionValue +
uint_to_minimal_bytes + uint_from_bytes.
Tests: option::tests::uint_zero_is_empty_byte_sequence,
uint_one_is_single_byte, uint_strips_leading_zero_bytes,
uint_from_bytes_decodes_minimal_form,
uint_from_bytes_handles_leading_zeros,
uint_from_bytes_rejects_more_than_8_bytes,
option_value_to_wire_bytes_matches_format.
Status: done
RFC 7252 §4 Message transmission
§4.1 Messages and endpoints
Spec: §4.1, p. 20 — endpoint identification via IP+port.
Repo: crates/coap-bridge/src/bridge.rs (endpoint as a Vec<u8> ID); the
UDP reactor deliberately lives at the caller layer via
crates/transport-udp/ — this separation allows no_std builds with their own
transport (e.g. an embedded stack without OS sockets). Spec §4.1 standardizes
the endpoint identification, not the UDP reactor itself.
Tests: crates/coap-bridge/src/bridge.rs::tests::{parses_topic_only, parses_topic_with_key, rejects_non_dds_path, bridge_apply_write_then_read_round_trip, bridge_observe_register_increments_observer_count}.
Status: done — endpoint tracking as a spec-conformant Vec
§4.2-§4.7 Reliability + deduplication + congestion
Spec: §4.2-§4.7, p. 21-26 — CON retry with exponential backoff up to
MAX_RETRANSMIT; §4.5 “The recipient […] SHOULD acknowledge each duplicate
copy of a Confirmable message […] but SHOULD process any request or response
in the message only once” — Message ID duplicates within EXCHANGE_LIFETIME
(CON) resp. NON_LIFETIME (NON); §4.7 NSTART as the cap on simultaneously
outstanding interactions towards one server.
Repo: crates/coap-bridge/src/reliability.rs::{ReliabilityTracker, PendingConfirmable, TickOutput} — send_confirmable/receive_ack/receive_rst/tick
cover the CON retry + ACK/RST path;
crates/coap-bridge/src/reliability.rs::{DuplicateDetector, DedupKind, Reception} with receive/remember_ack/evict_expired for the §4.5
deduplication (cached ACK instead of a second processing);
crates/coap-bridge/src/reliability.rs::OutstandingInteractions with
try_begin/end for the §4.7 NSTART cap per server.
Tests: crates/coap-bridge/src/reliability.rs::tests::{tick_before_timeout_does_nothing, tick_after_timeout_retransmits, exhausting_retransmits_times_out, interval_doubles_per_retransmit, send_then_ack_clears_pending, rst_clears_pending, duplicate_message_id_within_exchange_lifetime_is_detected, duplicate_entry_expires_after_its_lifetime, duplicate_detection_is_per_endpoint, duplicate_table_cap_bounds_memory, nstart_caps_outstanding_interactions_per_server}.
Status: done
§4.8 Transmission parameters
Spec: §4.8, p. 27-29 — Table 2: ACK_TIMEOUT 2 s, ACK_RANDOM_FACTOR 1.5,
MAX_RETRANSMIT 4, NSTART 1, DEFAULT_LEISURE 5 s, PROBING_RATE
1 byte/s. §4.8.2 derives from them:
MAX_TRANSMIT_SPAN = ACK_TIMEOUT * ((2 ** MAX_RETRANSMIT) - 1) * ACK_RANDOM_FACTOR (45 s), MAX_TRANSMIT_WAIT (93 s),
EXCHANGE_LIFETIME = MAX_TRANSMIT_SPAN + (2 * MAX_LATENCY) + PROCESSING_DELAY (247 s), NON_LIFETIME (145 s).
Repo: crates/coap-bridge/src/reliability.rs::{ACK_TIMEOUT_MS, ACK_RANDOM_FACTOR_NUM, ACK_RANDOM_FACTOR_DEN, MAX_RETRANSMIT, NSTART, DEFAULT_LEISURE_MS, PROBING_RATE_BYTES_PER_SEC, MAX_LATENCY_MS, PROCESSING_DELAY_MS, MAX_TRANSMIT_SPAN_MS, MAX_TRANSMIT_WAIT_MS, EXCHANGE_LIFETIME_MS, NON_LIFETIME_MS}; initial_interval uses
ACK_TIMEOUT * ACK_RANDOM_FACTOR as the first retry interval.
Tests: crates/coap-bridge/src/reliability.rs::tests::{transmission_parameters_match_spec_4_8_table_2, derived_transmission_parameters_follow_spec_4_8_2_formulas, backoff_schedule_follows_ack_timeout_and_random_factor} — the last one checks
the resulting retry sequence 3000/6000/12000/24000 ms and the give-up after
MAX_RETRANSMIT at MAX_TRANSMIT_WAIT.
Status: done
RFC 7252 §5 Request/response semantics
§5.1 Requests
Spec: §5.1, p. 35-36 — request definition: method code (1-31), token, options, payload.
Repo: method codes 1=GET, 2=POST, 3=PUT, 4=DELETE as CoapCode variants
in crates/coap-bridge/src/message.rs.
Tests: message::tests::well_known_codes_match_spec_values.
Status: done
§5.2 Responses
Spec: §5.2, p. 36 — response definition: response code (2.xx success, 4.xx client error, 5.xx server error), echoed token.
Repo: response codes as CoapCode variants (2.05 Content, 4.04 Not Found,
5.00 Internal Server Error, etc.).
Tests: message::tests::well_known_codes_match_spec_values.
Status: done
§5.3 Request/response matching
Spec: §5.3, p. 37-39 — token-based matching for async replies (piggybacked, separate, reset).
Repo: the token field in CoapMessage as a Vec<u8> with a length
constraint (TKL 0-8 bytes) + crates/coap-bridge/src/matching.rs::{PendingRequests, MatchError} with submit/complete/evict_expired and spec-§4.8
EXCHANGE_LIFETIME support; a DoS cap via max_pending.
Tests: matching::tests::{submit_empty_token_rejected, submit_then_complete_round_trip, complete_unknown_token_returns_none, submit_above_cap_rejected, submit_duplicate_token_rejected, evict_expired_removes_overdue_pendings, evict_keeps_fresh_pendings}.
Status: done — token wire format + pending-request map with lifetime eviction live.
§5.4 Options
Spec: §5.4, p. 39-43 — option-class properties: Critical/Elective, Unsafe/Safe, NoCacheKey, Repeatable.
Repo: option numbers in crates/coap-bridge/src/option.rs::numbers;
the property bits derived from the option number in
crates/coap-bridge/src/option.rs::{is_critical, is_unsafe, is_nocachekey, is_repeatable} following the §5.4.6 formula (Critical = (onum & 1),
UnSafe = (onum & 2), NoCacheKey = ((onum & 0x1e) == 0x1c)) plus the
same-named methods on CoapOption.
Tests: crates/coap-bridge/src/option.rs::tests::{critical_unsafe_nocachekey_bits_per_spec_5_4_6, repeatable_options_match_spec_table_4, observe_option_uses_number_6}.
Status: done
§5.5 Payloads and representations
Spec: §5.5.1/§5.5.3, p. 43-44 — the payload is a representation whose media type the Content-Format option names; §5.5.2 “If no Content-Format option is given, the payload of responses indicating a client or server error is a brief human-readable diagnostic message” in UTF-8.
Repo: crates/coap-bridge/src/message.rs::CoapMessage::payload as a
Vec<u8>; the Content-Format option (number 12) via
crates/coap-bridge/src/option.rs::CoapOption::content_format; the
payload-marker split in crates/coap-bridge/src/codec.rs.
Tests: crates/coap-bridge/src/codec.rs::tests::{representation_carries_content_format_per_spec_5_5, diagnostic_payload_of_error_response_carries_no_content_format, payload_marker_separates_options_from_payload}.
Status: done
§5.6 Caching
Spec: §5.6, p. 44-46 — freshness lifetime via the Max-Age option; validation via the ETag option.
Repo: Max-Age (number 14) + ETag (number 4) option numbers defined; cache
state logic in crates/coap-bridge/src/caching_proxy.rs::{CoapCache, CacheLookup, DEFAULT_MAX_AGE} with store/lookup/evict_expired_without_etag,
a DoS-cap FIFO eviction, and the spec-§5.6.1 default Max-Age (60s).
Tests: caching_proxy::tests::{empty_cache_returns_miss, store_then_fresh_lookup, stale_with_etag_yields_validation_path, stale_without_etag_yields_miss, cap_evicts_oldest, evict_expired_without_etag_keeps_revalidatable}.
Status: done — cache state + freshness + ETag-validation path live.
§5.7 Proxying
Spec: §5.7, p. 46-49 — the Proxy-Uri option, forward/reverse proxy, HTTP mapping.
Repo: the Proxy-Uri option (number 35) defined + proxy logic in
crates/coap-bridge/src/caching_proxy.rs::{ProxyConfig, ProxyMode} with
forward/reverse mode + a max_hops cap (spec §5.7.1 loop protection) + an
http_translation flag for the §10 path.
Tests: caching_proxy::tests::proxy_config_default_is_forward_coap_to_coap.
Status: partial — the Proxy-Uri option, forward/reverse mode and the hop limit are built as configuration; forwarding a request is missing (§5.7a).
§5.7a Forwarding through a proxy
Spec: §5.7, pp. 46-49 — a forward proxy performs the request against the target URI from Proxy-Uri, a reverse proxy maps it to an origin server, and both return the response.
Repo: —
Tests: —
Status: open — crates/coap-bridge/src/caching_proxy.rs holds only ProxyConfig/ProxyMode; no path forwards a request to the target.
§5.8 Method definitions
Spec: §5.8, p. 49-51 — GET/POST/PUT/DELETE semantics, idempotency.
Repo: method codes defined in crates/coap-bridge/src/message.rs + the method-property helpers
crates/coap-bridge/src/method_props.rs::{is_safe, is_idempotent, is_method}
with spec-conformant values (GET = safe + idempotent; PUT/DELETE = idempotent;
POST = neither).
Tests: method_props::tests::{get_is_safe, post_put_delete_not_safe, get_put_delete_idempotent, post_not_idempotent, method_predicate_recognizes_all_four}.
Status: done — codes + method properties (safety + idempotency) declared.
§5.9 Response code definitions
Spec: §5.9, p. 52-58 — the complete list of all response codes (2.xx, 4.xx, 5.xx) with meaning.
Repo: all important codes as CoapCode variants in crates/coap-bridge/src/message.rs.
Tests: message::tests::well_known_codes_match_spec_values.
Status: done
§5.10 Option definitions
Spec: §5.10, p. 53-67 — the number registry: Uri-Host (3), ETag (4), If-None-Match (5), Uri-Port (7), Location-Path (8), Uri-Path (11), Content-Format (12), Max-Age (14), Uri-Query (15), Accept (17), Location-Query (20), Proxy-Uri (35), Proxy-Scheme (39), Size1 (60). Plus If-Match (1).
Repo: crates/coap-bridge/src/option.rs::numbers with all constants +
the convenience constructors uri_path/content_format.
Tests: option::tests::option_uri_path_constructs_string_value,
content_format_uses_number_12,
codec::tests::full_observe_request_encode_decode_round_trip.
Status: done
RFC 7252 §6 CoAP URIs
§6.1-§6.5 CoAP URI scheme
Spec: §6, p. 67-72 — coap:// + coaps:// URI schemes.
Repo: crates/coap-bridge/src/uri.rs::{parse_coap_uri, CoapUri, default_port, UriError}. Default ports 5683 / 5684; path segments + query
parameters are split out (for direct mapping into the Uri-Path/Uri-Query
options); a fragment identifier is rejected (§6.1).
Tests: crates/coap-bridge/src/uri.rs::tests::{parses_basic_coap_uri, parses_coaps_default_port, parses_explicit_port, parses_query_params, parses_empty_path_when_no_slash, rejects_unknown_scheme, rejects_missing_host, rejects_invalid_port, rejects_fragment, default_port_returns_5684_for_coaps, round_trip_path_filtering_strips_empty_segments} (11).
Status: done — the coap/coaps URI-scheme parser live.
RFC 7252 §7 Discovery
§7.1-§7.2 Service + resource discovery
Spec: §7, p. 73-74 — multicast discovery + .well-known/core.
Repo: resource discovery via crates/coap-bridge/src/core_link.rs;
service discovery via multicast in multicast.rs::{ALL_NODES_LINK_LOCAL_V4, ALL_NODES_LINK_LOCAL_V6, ALL_NODES_SITE_LOCAL_V6, validate_multicast_request}
(see §8).
Tests: resource discovery:
crates/coap-bridge/src/core_link.rs::tests::{encode_simple_link_format, decode_round_trip_with_attrs}; service discovery:
crates/coap-bridge/src/multicast.rs::tests::{well_known_addresses_match_spec, valid_multicast_request_passes, multicast_request_must_not_be_confirmable}.
Status: partial — resource discovery via /.well-known/core and the multicast addresses are built and checked; service discovery by multicast needs the multicast reception of §8a.
RFC 7252 §8 Multicast CoAP
§8 Multicast operation
Spec: §8, p. 74-77 — IP-multicast semantics.
Repo: crates/coap-bridge/src/multicast.rs::{ALL_NODES_LINK_LOCAL_V4 ("224.0.1.187"), ALL_NODES_LINK_LOCAL_V6 ("FF02::FD"), ALL_NODES_SITE_LOCAL_V6 ("FF05::FD"), DEFAULT_LEISURE (5s), is_ipv4_multicast, is_ipv6_multicast, validate_multicast_request, leisure_delay, MulticastError} with spec-§8.1
NON-only validation + the §8.2 leisure-time helper.
Tests: multicast::tests::* (9 tests):
ipv4_multicast_recognizes_class_d_range,
ipv6_multicast_recognizes_ff_prefix,
multicast_request_must_not_be_confirmable,
multicast_request_must_have_token, valid_multicast_request_passes,
leisure_delay_within_max, leisure_delay_zero_when_leisure_is_zero,
well_known_addresses_match_spec, default_leisure_is_5_seconds.
Status: partial — multicast addresses, the NON-only check, the token requirement and the leisure time are built and checked; group join, sending and receiving in the daemon are missing (§8a).
§8a Multicast sending and receiving in the daemon
Spec: §8, pp. 74-77 — send and receive requests to an IP multicast group; a server answers after the leisure time.
Repo: —
Tests: —
Status: open — crates/coap-bridge/src/ joins no multicast group (no join_multicast_v4/join_multicast_v6); no socket path uses the helpers of multicast.rs.
RFC 7252 §9 Securing CoAP
§9 DTLS mode
Spec: §9, p. 77-86 — NoSec/PreSharedKey/RawPublicKey/Certificate modes.
Repo: crates/coap-bridge/src/dtls.rs::{DtlsMode, DtlsConfigError, validate_dtls_mode} with all four modes:
- NoSec (default port 5683).
- PreSharedKey { identity, key } (spec §9.1.1 — PSK ≥ 16 bytes recommended,
identity required).
- RawPublicKey { public_key, spki_der } (spec §9.1.2 — SubjectPublicKeyInfo
DER-encoded).
- Certificate { cert_chain, trust_anchors } (spec §9.1.3 — X.509 chain
validation against trust anchors).
An is_secure() predicate + default_port() (5683/5684) + name() for
logging. DTLS 1.2 transport in crates/coap-bridge/src/dtls_transport.rs
(feature dtls, webrtc-dtls) with PSK and certificate.
Tests: crates/coap-bridge/src/dtls.rs::tests::{nosec_is_not_secure, psk_is_secure, raw_public_key_is_secure, certificate_is_secure, validate_psk_short_key_rejected, validate_psk_empty_identity_rejected, validate_psk_valid, validate_certificate_empty_chain_rejected, validate_certificate_no_trust_anchors_rejected, validate_raw_public_key_empty_rejected, validate_nosec_passes}; crates/coap-bridge/tests/dtls_coap_e2e.rs::{dtls_coap_get_content_roundtrip, dtls_psk_handshake_carries_coap, dtls_psk_unknown_identity_is_refused, dtls_certificate_files_and_rotation_keep_sessions_alive}; crates/coap-bridge/tests/daemon_dtls_e2e.rs::daemon_serves_coaps_over_dtls_request_response_and_observe.
Status: partial — NoSec, PreSharedKey and Certificate run over the DTLS transport; RawPublicKey exists only as configuration (§9a).
§9a RawPublicKey mode in the DTLS transport
Spec: §9, p. 68 (text version) — “The NoSec and RawPublicKey modes are mandatory to implement for this specification.”; §9.1.3.2 RawPublicKey (RFC 7250).
Repo: —
Tests: —
Status: open — crates/coap-bridge/src/dtls.rs knows DtlsMode::RawPublicKey as configuration; crates/coap-bridge/src/dtls_transport.rs negotiates only PSK and certificate (DtlsPeerIdentity::{Psk, Certificate}), a handshake with a raw public key (RFC 7250) is missing.
RFC 7252 §10-§13 Inter-op + security + IANA + acknowledgments
§10 HTTP cross-protocol mapping
Spec: §10, p. 86-91 — HTTP↔︎CoAP translation for proxy use cases. §10.1 status-code mapping (Tab 8); §10.2 method mapping (Tab 9).
Repo: crates/coap-bridge/src/caching_proxy.rs::{http_status_to_coap, coap_to_http_status, http_method_to_coap, coap_method_to_http} with
spec-§10.1/§10.2-conformant mapping (200↔︎2.05, 404↔︎4.04, 500↔︎5.00, GET↔︎1,
POST↔︎2, PUT↔︎3, DELETE↔︎4, etc.).
Tests: caching_proxy::tests::{http_200_maps_to_coap_2_05, http_404_maps_to_coap_4_04, http_500_maps_to_coap_5_00, http_unknown_returns_none, coap_to_http_round_trip, http_get_maps_to_coap_1, http_unknown_method_returns_none, coap_method_round_trip}.
Status: done — HTTP status and method mapping bidirectional.
§11.1 Parsing and URI processing
Spec: §11.1, p. 80 (RFC) — “the URI processing code in CoAP implementations […] should be implemented with special care. CoAP access control implementations need to ensure they don’t introduce vulnerabilities through discrepancies between the code deriving access control decisions from a URI and the code finally serving up the resource addressed by the URI.”
Repo: crates/coap-bridge/src/codec.rs (decode),
crates/coap-bridge/src/uri.rs (parse_coap_uri).
Tests: crates/coap-bridge/tests/fuzz_smoke.rs::fuzz_coap_decode_no_panic,
crates/coap-bridge/src/uri.rs::tests::rejects_fragment.
Status: partial — decoder robustness and URI decomposition are tested; no test checks that the access decision (topic ACL) and serving use the same decomposition of the URI.
§11.2 Cache: no delivery to requests with lesser transport security
Spec: §11.2, p. 81 (RFC) — “a caching proxy MUST NOT make cached values available to requests that have lesser transport-security properties than those the proxy would require to perform request forwarding in the first place.”
Repo: —
Tests: —
Status: open — CoapCache (crates/coap-bridge/src/caching_proxy.rs)
stores and serves entries without regard to the transport security of
the request.
§11.2 coaps responses not in a shared cache
Spec: §11.2, p. 81 (RFC) — “responses to”coaps” identified requests are never “public” and thus MUST NOT be reused for shared caching, unless the cache is able to make equivalent access control decisions to the ones that led to the cached entry.”
Repo: —
Tests: —
Status: open — CoapCache does not distinguish responses to coap
and coaps requests.
§11.3 No large amplification without authentication
Spec: §11.3, p. 82 (RFC) — “large amplification factors SHOULD NOT be provided in the response if the request is not authenticated.”
Repo: —
Tests: —
Status: open — no code found that limits the response size for unauthenticated requests.
§11.3 Multicast requests only authenticated and only for specific resources
Spec: §11.3, p. 82 (RFC) — “CoAP servers SHOULD NOT accept multicast requests that can not be authenticated in some way […]. If possible, a CoAP server SHOULD limit the support for multicast requests to the specific resources where the feature is required.”
Repo: —
Tests: —
Status: open — the daemon (crates/coap-bridge/src/daemon/) does
not distinguish multicast from unicast requests and restricts multicast
neither to authenticated requests nor to resources.
§11.3 Detect the multicast destination via IPV6_RECVPKTINFO
Spec: §11.3, p. 82 (RFC) — “Implementations SHOULD make use of modern APIs such as IPV6_RECVPKTINFO [RFC3542], if available, to make this determination.”
Repo: —
Tests: —
Status: open — no code in crates/coap-bridge reads the destination
address of a received packet.
§11.4, §11.5 IP spoofing and cross-protocol attacks
Spec: §11.4–§11.5, p. 83–86 (RFC) — threat analysis (forged Reset/ACK/responses, multicast spoofing, DNS replies read as CoAP messages).
Repo: —
Tests: —
Status: n/a (informative) — description of attacks without a requirement of its own; the countermeasure named (non-trivial, randomized token) is §5.3.1.
§11.6 Constrained-node considerations
Spec: §11.6, p. 86 (RFC) — “the node MUST NOT be used for processes that require good entropy, such as key generation. […] Special care must be taken in implementation of cryptographic primitives.”
Repo: —
Tests: —
Status: open — the OSCORE cryptography uses aes, ccm, hmac and
sha2 from RustCrypto; no test checks constant-time behaviour. The
bridge generates no keys.
§12.1, §12.2, §12.4–§12.7 IANA registrations
Spec: §12.1–§12.2, §12.4–§12.7, p. 86–97 (RFC) — instructions to
IANA: code registries, option numbers registry, URI schemes coap and
coaps, ports 5683 and 5684.
Repo: —
Tests: —
Status: n/a (informative) — registration instructions to IANA; the values themselves are items §5.8, §5.9, §5.10 and §6.
§12.3 CoAP Content-Formats registry
Spec: §12.3, p. 91–93 (RFC) — initial entries: text/plain; charset=utf-8 = 0, application/link-format = 40, application/xml =
41, application/octet-stream = 42, application/exi = 47,
application/json = 50.
Repo: —
Tests: —
Status: open — crates/coap-bridge/src/daemon/server.rs sets 40 for
application/link-format, without a test; there are no constants for
the other entries.
§12.8 Multicast address registration
Spec: §12.8, p. 97 (RFC) — “All CoAP Nodes”: IPv4 224.0.1.187,
IPv6 FF0X::FD; “CoAP needs the Link-Local and Site-Local scopes only.”
Repo: crates/coap-bridge/src/multicast.rs (ALL_NODES_LINK_LOCAL_V4,
ALL_NODES_LINK_LOCAL_V6, ALL_NODES_SITE_LOCAL_V6).
Tests: crates/coap-bridge/src/multicast.rs::tests::well_known_addresses_match_spec.
Status: done
§13 Acknowledgements
Spec: §13, p. 97 (RFC) — acknowledgements.
Repo: —
Tests: —
Status: n/a (informative) — acknowledgements.
RFC 7641 §2 Observe option
§2 Observe option (number 6)
Spec: RFC 7641 §2, p. 4 — the Observe option (number 6) with values: 0 =
register, 1 = deregister, 2-0xFFFFFF = sequence number.
Repo: crates/coap-bridge/src/option.rs::CoapOption::observe(value) +
the numbers::OBSERVE constant.
Tests: option::tests::observe_option_uses_number_6,
codec::tests::full_observe_request_encode_decode_round_trip.
Status: done
RFC 7641 §3-§5 Notification + state + reordering
Spec: RFC 7641 §3.1/§3.4/§3.6, p. 7-14 — registration via Observe = 0,
a monotonically increasing sequence number modulo 2^24, and the reordering
rule: a new notification (V2, T2) is fresher than the stored one (V1, T1)
exactly when (V1 < V2 and V2 - V1 < 2^23) or (V1 > V2 and V1 - V2 > 2^23)
or T2 > T1 + 128 seconds; §3.6 deregistration ends the observe
relationship.
Repo: crates/coap-bridge/src/observe.rs::{ObserveRegistry, ObserverEntry}
with register/deregister/observers_of/next_seq for notification
sequencing per path; crates/coap-bridge/src/observe.rs::{notification_is_fresher, FRESHNESS_WINDOW_MS} for the §3.4 reordering rule.
Tests: crates/coap-bridge/src/observe.rs::tests::{register_then_observers_lists_one, next_seq_increments_per_observer, next_seq_wraps_at_24_bits, notifications_are_ordered_by_sequence_number_per_spec_3_4, wrapped_sequence_number_is_still_recognised_as_fresher, notification_older_than_the_freshness_window_is_always_accepted, deregister_ends_the_observe_relationship_per_spec_3_6}.
Status: done
Audit status
27 done / 5 partial / 10 open / 0 blocked / 4 n/a (informative).
Test run: cargo test -p zerodds-coap-bridge — 202 lib inline + 17
integration = 219 tests green, 0 failed, 3 ignored (interop tests against
external libcoap binaries). Modules with tests: blockwise, bridge,
caching_proxy, codec, core_link, daemon, dtls, matching,
message, method_props, multicast, observe, option, oscore,
reliability, uri.
Open items: coap-rfc-7252.open.en.md.
IETF CoAP RFC 7252 + RFC 7641 — Spec-Coverage
RFC 7252: The Constrained Application Protocol — IETF, June 2014 →
RFC 7641: Observing Resources in CoAP — IETF, September 2015 →
Kontext: CoAP ist eine RESTful-Spec für eingeschränkte Geräte.
ZeroDDS implementiert sie in crates/coap-bridge/: Wire-Codec (Section 3,
5.10, RFC 7641 §2) als no_std+alloc-Library, dazu Reliability,
Block-Wise Transfer (RFC 7959), Observe, einen DTLS-Transport (Feature
dtls), OSCORE und den Daemon.
Implementation:
crates/coap-bridge/· docs.rs — Codec, Transport-Bausteine und Daemonzerodds-coap-bridged.
RFC 7252 §1 Introduction
§1.1 Features
Spec: §1.1, S. 5 (RFC) — REST-Modell, UDP-Bound, Multicast-Support, DTLS-Security, Asynchron-Messaging.
Repo: crates/coap-bridge/src/lib.rs Crate-Doc.
Tests: REST-Methoden + Response-Klassen:
crates/coap-bridge/src/message.rs::tests::well_known_codes_match_spec_values;
Asynchron-Messaging (CON/NON/ACK/RST):
crates/coap-bridge/src/message.rs::tests::message_type_round_trips_via_bits;
Multicast-Support:
crates/coap-bridge/src/multicast.rs::tests::well_known_addresses_match_spec;
DTLS-Security:
crates/coap-bridge/src/dtls.rs::tests::psk_is_secure;
UDP-Bound (Default-Ports 5683/5684):
crates/coap-bridge/src/uri.rs::tests::default_port_returns_5684_for_coaps.
Status: done — Übersicht; Multicast und DTLS stehen als eigene Items (§8, §9, §11).
§1.2 Terminology
Spec: §1.2, S. 6-9 — Endpoint, Sender, Recipient, Token, Origin Server, Cacheable, Resource, etc.
Repo: —
Tests: —
Status: n/a (informative) — Glossar; semantischer Bezugspunkt ohne Code-Mapping.
RFC 7252 §2 Constrained Application Protocol
§2.1 Messaging Model
Spec: §2.1, S. 11 — CON/NON/ACK/RST.
Repo: crates/coap-bridge/src/message.rs::MessageType.
Tests: message::tests::message_type_round_trips_via_bits.
Status: done
§2.2 Request/Response Model
Spec: §2.2, S. 12 — Method-Codes + Response-Codes.
Repo: crates/coap-bridge/src/message.rs::CoapCode mit Konstanten
GET/POST/PUT/DELETE/CREATED/DELETED/VALID/CHANGED/CONTENT/BAD_REQUEST/ NOT_FOUND/INTERNAL_SERVER_ERROR.
Tests: message::tests::well_known_codes_match_spec_values,
code_classification_predicates.
Status: done
§2.3 Intermediaries and Caching
Spec: §2.3, S. 15 — Forward-Proxies, Caches.
Repo: crates/coap-bridge/src/caching_proxy.rs::{CoapCache, CacheLookup, ProxyConfig, ProxyMode} — Cache-Layer mit
Freshness-Tracking + Stale/Revalidate-Pfad; Proxy-Configuration
mit Forward-/Reverse-Mode + Hop-Count-Cap (Spec §5.7.1 Loop-Schutz).
Tests: crates/coap-bridge/src/caching_proxy.rs::tests::{empty_cache_returns_miss, store_then_fresh_lookup, stale_with_etag_yields_validation_path, stale_without_etag_yields_miss, cap_evicts_oldest, evict_expired_without_etag_keeps_revalidatable, proxy_config_default_is_forward_coap_to_coap}.
Status: done — Caching + Forward-Proxy-Configuration live.
§2.4 Resource Discovery
Spec: §2.4, S. 15 — .well-known/core (RFC 6690).
Repo: crates/coap-bridge/src/core_link.rs::{CoreLink, encode_links, decode_links}.
Tests: crates/coap-bridge/src/core_link.rs::tests::{encode_simple_link_format, encode_multiple_links_comma_separated, decode_round_trip_with_attrs, decode_handles_numeric_attr, decode_handles_quoted_string_with_comma, decode_rejects_uri_without_brackets, decode_attr_without_value_yields_empty, encode_escapes_inner_quotes}.
Status: done
RFC 7252 §3 Message Format
§3 Header-Format (Ver/T/TKL/Code/MID)
Spec: §3, S. 16 — 4-Byte-Fixed-Header. Version MUST be 1 (01 binary), TKL 0..=8 (9-15 reserved).
Repo: crates/coap-bridge/src/codec.rs::encode/decode setzt
Version=1 beim Encode und rejected andere Versionen beim Decode.
Tests: codec::tests::encodes_minimum_get_request_to_4_byte_header,
unsupported_version_decode_fails,
reserved_token_length_9_through_15_decode_fails,
token_length_above_8_is_rejected_on_encode.
Status: done
§3 Token
Spec: §3, S. 16 — Token 0..=8 Bytes nach Header.
Repo: crates/coap-bridge/src/message.rs::CoapMessage::token.
Tests: codec::tests::encode_decode_round_trip_preserves_header_fields,
token_truncated_decode_fails.
Status: done
§3 Payload Marker
Spec: §3, S. 16-17 — 0xFF markiert Beginn des Payload. “The
presence of a marker followed by a zero-length payload MUST be
processed as a message format error.”
Repo: crates/coap-bridge/src/codec.rs (Encode + Decode).
Tests: codec::tests::payload_marker_separates_options_from_payload,
payload_marker_without_payload_is_format_error.
Status: done
§3.1 Option Format (Delta-Encoding)
Spec: §3.1, S. 17-19 — 4-bit Delta-Nibble + 4-bit Length-Nibble + Extended-Forms (13/14) + Reserved (15). Options “MUST appear in order of their Option Numbers”.
Repo: crates/coap-bridge/src/codec.rs::encode_extended/ decode_extended. Encode sortiert Options vor Delta-Berechnung.
Tests: codec::tests::single_short_option_encodes_in_one_byte_header,
option_delta_extended_13_uses_one_extra_byte,
option_delta_extended_14_uses_two_extra_bytes,
option_length_extended_13_uses_one_extra_byte,
delta_encoding_sums_across_multiple_options,
options_are_sorted_on_encode.
Status: done
§3.2 Option Value Formats
Spec: §3.2, S. 19-20 — empty, opaque, uint, string. uint
“without leading zero bytes”; “MUST be prepared to process values with
leading zero bytes”.
Repo: crates/coap-bridge/src/option.rs::OptionValue +
uint_to_minimal_bytes + uint_from_bytes.
Tests: option::tests::uint_zero_is_empty_byte_sequence,
uint_one_is_single_byte, uint_strips_leading_zero_bytes,
uint_from_bytes_decodes_minimal_form,
uint_from_bytes_handles_leading_zeros,
uint_from_bytes_rejects_more_than_8_bytes,
option_value_to_wire_bytes_matches_format.
Status: done
RFC 7252 §4 Message Transmission
§4.1 Messages and Endpoints
Spec: §4.1, S. 20 — Endpoint-Identifikation via IP+Port.
Repo: crates/coap-bridge/src/bridge.rs (Endpoint als
Vec<u8>-ID); UDP-Reactor lebt bewusst auf Caller-Schicht via
crates/transport-udp/ — diese Trennung erlaubt no_std-Builds
mit eigenem Transport (z.B. embedded-Stack ohne OS-Sockets).
Spec §4.1 normiert die Endpoint-Identifikation, nicht den UDP-
Reactor selbst.
Tests: crates/coap-bridge/src/bridge.rs::tests::{parses_topic_only, parses_topic_with_key, rejects_non_dds_path, bridge_apply_write_then_read_round_trip, bridge_observe_register_increments_observer_count}.
Status: done — Endpoint-Tracking als spec-konforme Vec
§4.2-§4.7 Reliability + Deduplication + Congestion
Spec: §4.2-§4.7, S. 21-26 — CON-Retry mit exponentiellem Backoff bis
MAX_RETRANSMIT; §4.5 „The recipient […] SHOULD acknowledge each
duplicate copy of a Confirmable message […] but SHOULD process any
request or response in the message only once” — Message-ID-Duplikate
innerhalb EXCHANGE_LIFETIME (CON) bzw. NON_LIFETIME (NON); §4.7
NSTART als Obergrenze gleichzeitig ausstehender Interaktionen
gegenüber einem Server.
Repo: crates/coap-bridge/src/reliability.rs::{ReliabilityTracker, PendingConfirmable, TickOutput} — send_confirmable/receive_ack/
receive_rst/tick decken CON-Retry + ACK/RST-Pfad ab;
crates/coap-bridge/src/reliability.rs::{DuplicateDetector, DedupKind, Reception} mit receive/remember_ack/evict_expired für die §4.5-
Deduplikation (ACK aus dem Cache statt zweiter Verarbeitung);
crates/coap-bridge/src/reliability.rs::OutstandingInteractions mit
try_begin/end für die §4.7-NSTART-Schranke pro Server.
Tests: crates/coap-bridge/src/reliability.rs::tests::{tick_before_timeout_does_nothing, tick_after_timeout_retransmits, exhausting_retransmits_times_out, interval_doubles_per_retransmit, send_then_ack_clears_pending, rst_clears_pending, duplicate_message_id_within_exchange_lifetime_is_detected, duplicate_entry_expires_after_its_lifetime, duplicate_detection_is_per_endpoint, duplicate_table_cap_bounds_memory, nstart_caps_outstanding_interactions_per_server}.
Status: done
§4.8 Transmission Parameters
Spec: §4.8, S. 27-29 — Tab. 2: ACK_TIMEOUT 2 s, ACK_RANDOM_FACTOR
1.5, MAX_RETRANSMIT 4, NSTART 1, DEFAULT_LEISURE 5 s,
PROBING_RATE 1 Byte/s. §4.8.2 leitet daraus ab:
MAX_TRANSMIT_SPAN = ACK_TIMEOUT * ((2 ** MAX_RETRANSMIT) - 1) * ACK_RANDOM_FACTOR (45 s), MAX_TRANSMIT_WAIT (93 s),
EXCHANGE_LIFETIME = MAX_TRANSMIT_SPAN + (2 * MAX_LATENCY) + PROCESSING_DELAY (247 s), NON_LIFETIME (145 s).
Repo: crates/coap-bridge/src/reliability.rs::{ACK_TIMEOUT_MS, ACK_RANDOM_FACTOR_NUM, ACK_RANDOM_FACTOR_DEN, MAX_RETRANSMIT, NSTART, DEFAULT_LEISURE_MS, PROBING_RATE_BYTES_PER_SEC, MAX_LATENCY_MS, PROCESSING_DELAY_MS, MAX_TRANSMIT_SPAN_MS, MAX_TRANSMIT_WAIT_MS, EXCHANGE_LIFETIME_MS, NON_LIFETIME_MS}; initial_interval setzt
ACK_TIMEOUT * ACK_RANDOM_FACTOR als erstes Retry-Intervall.
Tests: crates/coap-bridge/src/reliability.rs::tests::{transmission_parameters_match_spec_4_8_table_2, derived_transmission_parameters_follow_spec_4_8_2_formulas, backoff_schedule_follows_ack_timeout_and_random_factor} — der letzte
prüft die daraus folgende Retry-Folge 3000/6000/12000/24000 ms und den
Abbruch nach MAX_RETRANSMIT bei MAX_TRANSMIT_WAIT.
Status: done
RFC 7252 §5 Request/Response Semantics
§5.1 Requests
Spec: §5.1, S. 35-36 — Request-Definition: Method-Code (1-31), Token, Options, Payload.
Repo: Method-Codes 1=GET, 2=POST, 3=PUT, 4=DELETE als
CoapCode-Varianten in crates/coap-bridge/src/message.rs.
Tests: message::tests::well_known_codes_match_spec_values.
Status: done
§5.2 Responses
Spec: §5.2, S. 36 — Response-Definition: Response-Code (2.xx Success, 4.xx Client-Error, 5.xx Server-Error), Echoed Token.
Repo: Response-Codes als CoapCode-Varianten (2.05 Content,
4.04 Not Found, 5.00 Internal Server Error etc.).
Tests: message::tests::well_known_codes_match_spec_values.
Status: done
§5.3 Request/Response Matching
Spec: §5.3, S. 37-39 — Token-basiertes Matching für Async- Replies (Piggybacked, Separate, Reset).
Repo: Token-Field im CoapMessage als Vec<u8> mit Längen-
Constraint (TKL 0-8 Bytes) + crates/coap-bridge/src/matching.rs:: {PendingRequests, MatchError} mit submit/complete/
evict_expired und Spec-§4.8-EXCHANGE_LIFETIME-Support; DoS-Cap
über max_pending.
Tests: matching::tests::{submit_empty_token_rejected, submit_then_complete_round_trip, complete_unknown_token_returns_none, submit_above_cap_rejected, submit_duplicate_token_rejected, evict_expired_removes_overdue_pendings, evict_keeps_fresh_pendings}.
Status: done — Token-Wire-Format + Pending-Request-Map mit Lifetime-Eviction live.
§5.4 Options
Spec: §5.4, S. 39-43 — Option-Class-Properties: Critical/Elective, Unsafe/Safe, NoCacheKey, Repeatable.
Repo: Option-Numbers in crates/coap-bridge/src/option.rs::numbers;
Property-Bits aus der Option-Number in
crates/coap-bridge/src/option.rs::{is_critical, is_unsafe, is_nocachekey, is_repeatable} nach der §5.4.6-Formel
(Critical = (onum & 1), UnSafe = (onum & 2),
NoCacheKey = ((onum & 0x1e) == 0x1c)) plus die gleichnamigen
Methoden auf CoapOption.
Tests: crates/coap-bridge/src/option.rs::tests::{critical_unsafe_nocachekey_bits_per_spec_5_4_6, repeatable_options_match_spec_table_4, observe_option_uses_number_6}.
Status: done
§5.5 Payloads and Representations
Spec: §5.5.1/§5.5.3, S. 43-44 — Payload als Repräsentation, deren Medientyp die Content-Format-Option benennt; §5.5.2 „If no Content-Format option is given, the payload of responses indicating a client or server error is a brief human-readable diagnostic message” in UTF-8.
Repo: crates/coap-bridge/src/message.rs::CoapMessage::payload als
Vec<u8>; Content-Format-Option (Number 12) über
crates/coap-bridge/src/option.rs::CoapOption::content_format;
Payload-Marker-Trennung in crates/coap-bridge/src/codec.rs.
Tests: crates/coap-bridge/src/codec.rs::tests::{representation_carries_content_format_per_spec_5_5, diagnostic_payload_of_error_response_carries_no_content_format, payload_marker_separates_options_from_payload}.
Status: done
§5.6 Caching
Spec: §5.6, S. 44-46 — Freshness-Lifetime via Max-Age-Option; Validation via ETag-Option.
Repo: Max-Age (Number 14) + ETag (Number 4) Option-Numbers
definiert; Cache-State-Logik in
crates/coap-bridge/src/caching_proxy.rs::{CoapCache, CacheLookup, DEFAULT_MAX_AGE} mit store/lookup/evict_expired_without_etag,
DoS-Cap-FIFO-Eviction und Spec-§5.6.1-Default-Max-Age (60s).
Tests: caching_proxy::tests::{empty_cache_returns_miss, store_then_fresh_lookup, stale_with_etag_yields_validation_path, stale_without_etag_yields_miss, cap_evicts_oldest, evict_expired_without_etag_keeps_revalidatable}.
Status: done — Cache-State + Freshness + ETag-Validation-Pfad live.
§5.7 Proxying
Spec: §5.7, S. 46-49 — Proxy-Uri-Option, Forward-/Reverse-Proxy, HTTP-Mapping.
Repo: Proxy-Uri-Option (Number 35) definiert + Proxy-Logik in
crates/coap-bridge/src/caching_proxy.rs::{ProxyConfig, ProxyMode}
mit Forward/Reverse-Mode + max_hops-Cap (Spec §5.7.1 Loop-Schutz)
+ http_translation-Flag für §10-Pfad.
Tests: caching_proxy::tests::proxy_config_default_is_forward_coap_to_coap.
Status: partial — Proxy-Uri-Option, Forward-/Reverse-Modus und Hop-Grenze sind als Konfiguration gebaut; das Weiterleiten eines Requests fehlt (§5.7a).
§5.7a Weiterleiten durch einen Proxy
Spec: §5.7, S. 46-49 — ein Forward-Proxy führt den Request mit der Ziel-URI aus Proxy-Uri aus, ein Reverse-Proxy bildet ihn auf einen Ursprungs-Server ab, und beide liefern die Response zurück.
Repo: —
Tests: —
Status: open — crates/coap-bridge/src/caching_proxy.rs hält nur ProxyConfig/ProxyMode; kein Pfad sendet einen Request an das Ziel weiter.
§5.8 Method Definitions
Spec: §5.8, S. 49-51 — GET/POST/PUT/DELETE-Semantik, Idempotency.
Repo: Method-Codes definiert in crates/coap-bridge/src/message.rs + Method-Property-
Helpers crates/coap-bridge/src/method_props.rs::{is_safe, is_idempotent, is_method} mit Spec-konformen Werten (GET = safe +
idempotent; PUT/DELETE = idempotent; POST = weder).
Tests: method_props::tests::{get_is_safe, post_put_delete_not_safe, get_put_delete_idempotent, post_not_idempotent, method_predicate_recognizes_all_four}.
Status: done — Codes + Method-Properties (Safety + Idempotency) ausgewiesen.
§5.9 Response Code Definitions
Spec: §5.9, S. 52-58 — vollständige Liste aller Response-Codes (2.xx, 4.xx, 5.xx) mit Bedeutung.
Repo: Alle wichtigen Codes als CoapCode-Varianten in
crates/coap-bridge/src/message.rs.
Tests: message::tests::well_known_codes_match_spec_values.
Status: done
§5.10 Option Definitions
Spec: §5.10, S. 53-67 — Number-Registry: Uri-Host (3), ETag (4), If-None-Match (5), Uri-Port (7), Location-Path (8), Uri-Path (11), Content-Format (12), Max-Age (14), Uri-Query (15), Accept (17), Location-Query (20), Proxy-Uri (35), Proxy-Scheme (39), Size1 (60). Plus If-Match (1).
Repo: crates/coap-bridge/src/option.rs::numbers mit allen
Konstanten + Convenience-Konstruktoren uri_path/content_format.
Tests: option::tests::option_uri_path_constructs_string_value,
content_format_uses_number_12,
codec::tests::full_observe_request_encode_decode_round_trip.
Status: done
RFC 7252 §6 CoAP URIs
§6.1-§6.5 CoAP-URI-Scheme
Spec: §6, S. 67-72 — coap:// + coaps:// URI-Schemen.
Repo: crates/coap-bridge/src/uri.rs::{parse_coap_uri, CoapUri, default_port, UriError}. Default-Ports 5683 / 5684; Path-Segmente
+ Query-Parameter werden aufgeteilt (zur direkten Mapping in
Uri-Path/Uri-Query-Options); Fragment-Identifier rejected (§6.1).
Tests: crates/coap-bridge/src/uri.rs::tests::{parses_basic_coap_uri, parses_coaps_default_port, parses_explicit_port, parses_query_params, parses_empty_path_when_no_slash, rejects_unknown_scheme, rejects_missing_host, rejects_invalid_port, rejects_fragment, default_port_returns_5684_for_coaps, round_trip_path_filtering_strips_empty_segments} (11).
Status: done — coap/coaps URI-Scheme-Parser live.
RFC 7252 §7 Discovery
§7.1-§7.2 Service + Resource Discovery
Spec: §7, S. 73-74 — Multicast-Discovery + .well-known/core.
Repo: Resource-Discovery via crates/coap-bridge/src/core_link.rs;
Service-Discovery via Multicast in multicast.rs::{ALL_NODES_LINK_LOCAL_V4, ALL_NODES_LINK_LOCAL_V6, ALL_NODES_SITE_LOCAL_V6, validate_multicast_request} (siehe §8).
Tests: Resource-Discovery:
crates/coap-bridge/src/core_link.rs::tests::{encode_simple_link_format, decode_round_trip_with_attrs}; Service-Discovery:
crates/coap-bridge/src/multicast.rs::tests::{well_known_addresses_match_spec, valid_multicast_request_passes, multicast_request_must_not_be_confirmable}.
Status: partial — Resource-Discovery über /.well-known/core und die Multicast-Adressen sind gebaut und geprüft; Service-Discovery per Multicast braucht den Multicast-Empfang aus §8a.
RFC 7252 §8 Multicast CoAP
§8 Multicast Operation
Spec: §8, S. 74-77 — IP-Multicast-Semantik.
Repo: crates/coap-bridge/src/multicast.rs::{ALL_NODES_LINK_LOCAL_V4 ("224.0.1.187"), ALL_NODES_LINK_LOCAL_V6 ("FF02::FD"), ALL_NODES_SITE_LOCAL_V6 ("FF05::FD"), DEFAULT_LEISURE (5s), is_ipv4_multicast, is_ipv6_multicast, validate_multicast_request, leisure_delay, MulticastError} mit Spec-§8.1-konformer NON-only-
Validation + §8.2 Leisure-Time-Helper.
Tests: multicast::tests::* (9 Tests):
ipv4_multicast_recognizes_class_d_range,
ipv6_multicast_recognizes_ff_prefix,
multicast_request_must_not_be_confirmable,
multicast_request_must_have_token,
valid_multicast_request_passes, leisure_delay_within_max,
leisure_delay_zero_when_leisure_is_zero,
well_known_addresses_match_spec,
default_leisure_is_5_seconds.
Status: partial — Multicast-Adressen, NON-only-Prüfung, Token-Pflicht und Leisure-Zeit sind gebaut und geprüft; Gruppenbeitritt, Senden und Empfangen im Daemon fehlen (§8a).
§8a Multicast-Versand und -Empfang im Daemon
Spec: §8, S. 74-77 — Requests an eine IP-Multicast-Gruppe senden und empfangen; ein Server antwortet nach der Leisure-Zeit.
Repo: —
Tests: —
Status: open — crates/coap-bridge/src/ tritt keiner Multicast-Gruppe bei (kein join_multicast_v4/join_multicast_v6); die Helfer aus multicast.rs werden von keinem Socket-Pfad benutzt.
RFC 7252 §9 Securing CoAP
§9 DTLS Mode
Spec: §9, S. 77-86 — NoSec/PreSharedKey/RawPublicKey/Certificate- Modi.
Repo: crates/coap-bridge/src/dtls.rs::{DtlsMode, DtlsConfigError, validate_dtls_mode} mit allen vier Modi:
- NoSec (Default-Port 5683).
- PreSharedKey { identity, key } (Spec §9.1.1 — PSK ≥ 16 bytes
empfohlen, identity required).
- RawPublicKey { public_key, spki_der } (Spec §9.1.2 — SubjectPublicKeyInfo
DER-encoded).
- Certificate { cert_chain, trust_anchors } (Spec §9.1.3 —
X.509-Chain-Validation gegen Trust-Anchors).
is_secure()-Predicate + default_port() (5683/5684) + name()
für Logging. DTLS-1.2-Transport in crates/coap-bridge/src/dtls_transport.rs
(Feature dtls, webrtc-dtls) mit PSK und Zertifikat.
Tests: crates/coap-bridge/src/dtls.rs::tests::{nosec_is_not_secure, psk_is_secure, raw_public_key_is_secure, certificate_is_secure, validate_psk_short_key_rejected, validate_psk_empty_identity_rejected, validate_psk_valid, validate_certificate_empty_chain_rejected, validate_certificate_no_trust_anchors_rejected, validate_raw_public_key_empty_rejected, validate_nosec_passes}; crates/coap-bridge/tests/dtls_coap_e2e.rs::{dtls_coap_get_content_roundtrip, dtls_psk_handshake_carries_coap, dtls_psk_unknown_identity_is_refused, dtls_certificate_files_and_rotation_keep_sessions_alive}; crates/coap-bridge/tests/daemon_dtls_e2e.rs::daemon_serves_coaps_over_dtls_request_response_and_observe.
Status: partial — NoSec, PreSharedKey und Certificate laufen über den DTLS-Transport; RawPublicKey ist nur als Konfiguration vorhanden (§9a).
§9a RawPublicKey-Modus im DTLS-Transport
Spec: §9, S. 68 (Textfassung) — „The NoSec and RawPublicKey modes are mandatory to implement for this specification.“; §9.1.3.2 RawPublicKey (RFC 7250).
Repo: —
Tests: —
Status: open — crates/coap-bridge/src/dtls.rs kennt DtlsMode::RawPublicKey als Konfiguration; crates/coap-bridge/src/dtls_transport.rs handelt nur PSK und Zertifikat aus (DtlsPeerIdentity::{Psk, Certificate}), ein Handshake mit Raw Public Key (RFC 7250) fehlt.
RFC 7252 §10-§13 Inter-Op + Security + IANA + Acknowledgments
§10 HTTP Cross-Proto-Mapping
Spec: §10, S. 86-91 — HTTP↔︎CoAP-Translation für Proxy-Use-Cases. §10.1 Status-Code-Mapping (Tab 8); §10.2 Method-Mapping (Tab 9).
Repo: crates/coap-bridge/src/caching_proxy.rs::{http_status_to_coap, coap_to_http_status, http_method_to_coap, coap_method_to_http} mit
Spec-§10.1/§10.2-konformem Mapping (200↔︎2.05, 404↔︎4.04, 500↔︎5.00,
GET↔︎1, POST↔︎2, PUT↔︎3, DELETE↔︎4 etc.).
Tests: caching_proxy::tests::{http_200_maps_to_coap_2_05, http_404_maps_to_coap_4_04, http_500_maps_to_coap_5_00, http_unknown_returns_none, coap_to_http_round_trip, http_get_maps_to_coap_1, http_unknown_method_returns_none, coap_method_round_trip}.
Status: done — HTTP-Status- und Method-Mapping bidirektional.
§11.1 Parsing und URI-Verarbeitung
Spec: §11.1, S. 80 (RFC) — “the URI processing code in CoAP implementations […] should be implemented with special care. CoAP access control implementations need to ensure they don’t introduce vulnerabilities through discrepancies between the code deriving access control decisions from a URI and the code finally serving up the resource addressed by the URI.”
Repo: crates/coap-bridge/src/codec.rs (decode),
crates/coap-bridge/src/uri.rs (parse_coap_uri).
Tests: crates/coap-bridge/tests/fuzz_smoke.rs::fuzz_coap_decode_no_panic,
crates/coap-bridge/src/uri.rs::tests::rejects_fragment.
Status: partial — Robustheit des Decoders und die URI-Zerlegung sind getestet; kein Test prüft, dass Zugriffsentscheidung (Topic-ACL) und Auslieferung dieselbe Zerlegung der URI verwenden.
§11.2 Cache: keine Auslieferung an Anfragen mit geringerer Transportsicherheit
Spec: §11.2, S. 81 (RFC) — “a caching proxy MUST NOT make cached values available to requests that have lesser transport-security properties than those the proxy would require to perform request forwarding in the first place.”
Repo: —
Tests: —
Status: open — CoapCache (crates/coap-bridge/src/caching_proxy.rs)
speichert und liefert Einträge ohne Bezug auf die Transportsicherheit
der Anfrage.
§11.2 coaps-Antworten nicht im geteilten Cache
Spec: §11.2, S. 81 (RFC) — “responses to”coaps” identified requests are never “public” and thus MUST NOT be reused for shared caching, unless the cache is able to make equivalent access control decisions to the ones that led to the cached entry.”
Repo: —
Tests: —
Status: open — CoapCache unterscheidet nicht zwischen Antworten auf
coap- und coaps-Anfragen.
§11.3 Keine große Verstärkung ohne Authentifizierung
Spec: §11.3, S. 82 (RFC) — “large amplification factors SHOULD NOT be provided in the response if the request is not authenticated.”
Repo: —
Tests: —
Status: open — kein Code gefunden, der die Antwortgröße für nicht authentifizierte Anfragen begrenzt.
§11.3 Multicast-Anfragen nur authentifiziert und nur für bestimmte Ressourcen
Spec: §11.3, S. 82 (RFC) — “CoAP servers SHOULD NOT accept multicast requests that can not be authenticated in some way […]. If possible, a CoAP server SHOULD limit the support for multicast requests to the specific resources where the feature is required.”
Repo: —
Tests: —
Status: open — der Daemon (crates/coap-bridge/src/daemon/)
unterscheidet Multicast- und Unicast-Anfragen nicht und schränkt
Multicast weder auf authentifizierte Anfragen noch auf Ressourcen ein.
§11.3 Multicast-Ziel über IPV6_RECVPKTINFO erkennen
Spec: §11.3, S. 82 (RFC) — “Implementations SHOULD make use of modern APIs such as IPV6_RECVPKTINFO [RFC3542], if available, to make this determination.”
Repo: —
Tests: —
Status: open — kein Code in crates/coap-bridge liest die
Zieladresse eines empfangenen Pakets.
§11.4, §11.5 IP-Spoofing und Cross-Protocol-Angriffe
Spec: §11.4–§11.5, S. 83–86 (RFC) — Bedrohungsanalyse (gefälschte Reset/ACK/Antworten, Multicast-Spoofing, DNS-Antworten als CoAP-Nachricht).
Repo: —
Tests: —
Status: n/a (informative) — Beschreibung von Angriffen ohne eigene Anforderung; die genannte Gegenmaßnahme (nicht triviales, zufälliges Token) ist §5.3.1.
§11.6 Constrained-Node Considerations
Spec: §11.6, S. 86 (RFC) — “the node MUST NOT be used for processes that require good entropy, such as key generation. […] Special care must be taken in implementation of cryptographic primitives.”
Repo: —
Tests: —
Status: open — die OSCORE-Kryptografie verwendet aes, ccm,
hmac und sha2 aus RustCrypto; kein Test prüft die Laufzeitkonstanz.
Die Bridge erzeugt keine Schlüssel.
§12.1, §12.2, §12.4–§12.7 IANA-Registrierungen
Spec: §12.1–§12.2, §12.4–§12.7, S. 86–97 (RFC) — Anweisungen an die
IANA: Code-Registries, Option-Numbers-Registry, URI-Schemes coap und
coaps, Ports 5683 und 5684.
Repo: —
Tests: —
Status: n/a (informative) — Registrierungsanweisungen an die IANA; die Werte selbst sind als Items §5.8, §5.9, §5.10 und §6 geführt.
§12.3 CoAP Content-Formats Registry
Spec: §12.3, S. 91–93 (RFC) — Anfangseinträge: text/plain; charset=utf-8 = 0, application/link-format = 40, application/xml =
41, application/octet-stream = 42, application/exi = 47,
application/json = 50.
Repo: —
Tests: —
Status: open — crates/coap-bridge/src/daemon/server.rs setzt 40 für
application/link-format, ohne Test; für die übrigen Einträge gibt es
keine Konstanten.
§12.8 Multicast Address Registration
Spec: §12.8, S. 97 (RFC) — “All CoAP Nodes”: IPv4 224.0.1.187,
IPv6 FF0X::FD; “CoAP needs the Link-Local and Site-Local scopes only.”
Repo: crates/coap-bridge/src/multicast.rs (ALL_NODES_LINK_LOCAL_V4,
ALL_NODES_LINK_LOCAL_V6, ALL_NODES_SITE_LOCAL_V6).
Tests: crates/coap-bridge/src/multicast.rs::tests::well_known_addresses_match_spec.
Status: done
§13 Acknowledgements
Spec: §13, S. 97 (RFC) — Danksagung.
Repo: —
Tests: —
Status: n/a (informative) — Danksagung.
RFC 7641 §2 Observe Option
§2 Observe Option (Number 6)
Spec: RFC 7641 §2, S. 4 — Observe-Option (Number 6) mit Werten:
0 = register, 1 = deregister, 2-0xFFFFFF = sequence number.
Repo: crates/coap-bridge/src/option.rs::CoapOption::observe(value)
+ numbers::OBSERVE Konstante.
Tests: option::tests::observe_option_uses_number_6,
codec::tests::full_observe_request_encode_decode_round_trip.
Status: done
RFC 7641 §3-§5 Notification + State + Reordering
Spec: RFC 7641 §3.1/§3.4/§3.6, S. 7-14 — Registrierung über
Observe = 0, monoton steigende Sequenznummer modulo 2^24, und die
Reordering-Regel: eine neue Notification (V2, T2) ist frischer als die
gespeicherte (V1, T1) genau dann, wenn (V1 < V2 and V2 - V1 < 2^23)
oder (V1 > V2 and V1 - V2 > 2^23) oder T2 > T1 + 128 seconds;
§3.6 Deregistrierung beendet die Observe-Beziehung.
Repo: crates/coap-bridge/src/observe.rs::{ObserveRegistry, ObserverEntry} mit register/deregister/observers_of/next_seq
für Notification-Sequencing pro Path;
crates/coap-bridge/src/observe.rs::{notification_is_fresher, FRESHNESS_WINDOW_MS} für die §3.4-Reordering-Regel.
Tests: crates/coap-bridge/src/observe.rs::tests::{register_then_observers_lists_one, next_seq_increments_per_observer, next_seq_wraps_at_24_bits, notifications_are_ordered_by_sequence_number_per_spec_3_4, wrapped_sequence_number_is_still_recognised_as_fresher, notification_older_than_the_freshness_window_is_always_accepted, deregister_ends_the_observe_relationship_per_spec_3_6}.
Status: done
Audit-Status
27 done / 5 partial / 10 open / 0 blocked / 4 n/a (informative).
Test-Lauf: cargo test -p zerodds-coap-bridge — 202 lib-Inline +
17 Integration = 219 Tests grün, 0 failed, 3 ignored (Interop-Tests
gegen externe libcoap-Binaries). Module mit Tests: blockwise,
bridge, caching_proxy, codec, core_link, daemon, dtls,
matching, message, method_props, multicast, observe,
option, oscore, reliability, uri.
Offene Punkte: coap-rfc-7252.open.md.