| Internet-Draft | CIRP | February 2026 |
| Verma | Expires 26 August 2026 | [Page] |
This document specifies a transport-layer protocol for routing capability-oriented intent between cryptographically identified endpoints across heterogeneous trust domains. The protocol defines capability identifiers with mandatory versioning, scoped discovery across five visibility levels, ticket-based session authorization, negotiated cryptographic suites including hybrid post-quantum key establishment, encrypted peer-to-peer session establishment, and mutually attested invocation receipts with hash-chained integrity. Payload semantics are opaque to the transport layer.¶
This revision clarifies session-level capability binding semantics, aligns discovery behavior with deployed FIND_EX wire formats, and refines session teardown security properties.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 26 August 2026.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
Existing transport protocols provide general-purpose data delivery between network endpoints. They do not address the requirements of systems that need to discover capabilities by function, route structured invocations to providers of those capabilities, and produce cryptographically verifiable records of fulfillment. These requirements arise in domains including autonomous systems, industrial control, medical device coordination, software service composition, and other environments where heterogeneous endpoints must locate and invoke capabilities across trust boundaries.¶
The Capability-Oriented Intent Routing Protocol (CIRP) is a transport-layer protocol that addresses these requirements. It provides: structured capability identifiers with mandatory versioning; scoped discovery that respects organizational and cryptographic trust boundaries; ticket-based session authorization that removes the authorizing registry from the data path; encrypted peer-to-peer sessions with cryptographic agility including hybrid post-quantum key exchange; typed invocation envelopes with opaque payloads; and mutually attested fulfillment receipts.¶
CIRP operates at the transport layer. It does not interpret payload semantics, evaluate business logic, rank providers, manage economic relationships, or implement domain-specific processing. These concerns belong to application layers built above the transport. The protocol is designed to carry executable intent for any domain: the payload may contain JSON, binary protocol encodings, robotics command sequences, medical device instructions, industrial control messages, or any other octet sequence. The concept of an "Internet of Intent" describes a network infrastructure where such invocations can be routed across heterogeneous trust domains using a common transport protocol.¶
This document specifies the protocol messages, encoding formats, cryptographic operations, and security properties of CIRP. It defines an initial transport binding for UDP and establishes IANA registries for cryptographic suites, capability URI schemes, and protocol parameters.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
The following topics are explicitly outside the scope of this specification:¶
CIRP defines a layered architecture for routing capability-oriented intent between cryptographically identified endpoints. The architecture separates concerns into distinct layers, each with well-defined responsibilities and trust boundaries.¶
The protocol operates at Layer 1 in the following conceptual stack:¶
+---------------------------------------------------+ | Layer 3: Domain Applications | | DSL-specific logic, vertical solutions | +---------------------------------------------------+ | Layer 2: Implementation Ecosystems | | Agent frameworks, SDKs, runtime environments | +---------------------------------------------------+ | Layer 1: Intent Routing Transport [this document]| | Capability addressing, discovery, sessions, | | invocation envelopes, receipts | +---------------------------------------------------+ | Layer 0: Cryptographic Identity | | Ed25519 keypairs, EID derivation | +---------------------------------------------------+¶
This document specifies Layer 1. Layers above the transport are unconstrained by this specification: any agent framework, domain-specific language, or application architecture may operate over CIRP provided it uses the defined capability addressing, session establishment, and invocation envelope formats.¶
Layer 0 is the identity foundation. An Endpoint Identifier (EID) is the Ed25519 public key of a node. Because EID equals the public key, identity verification requires no certificate authority, no public key infrastructure, and no trusted third party. A node proves its identity by signing messages with the corresponding private key.¶
Three roles participate in the protocol:¶
A single endpoint MAY act as both Consumer and Provider simultaneously for different capabilities. The protocol does not impose a fixed client-server relationship; any endpoint with a cryptographic identity may assume either role.¶
The protocol operates under the following trust model:¶
CIRP separates protocol operations into two planes with distinct security properties and operational characteristics.¶
The control plane handles registry-mediated operations: presence registration, capability advertisement, discovery queries, admission control, and ConnectTicket issuance. Control plane messages are exchanged between endpoints and registries.¶
Control plane messages are small, fixed-structure, and designed to fit within a single transport datagram for typical deployments. This design prioritizes low-latency registry interactions and avoids fragmentation on common network paths.¶
The control plane does not carry invocation content. It handles only the metadata necessary for discovery and session authorization.¶
The data plane handles peer-to-peer communication between consumer and provider after session establishment. All data plane traffic is encrypted using session keys derived during key exchange (Section 7.4). The registry is not involved in data plane operations: it does not relay data, does not possess session keys, and cannot observe invocation content.¶
The data plane carries invocation envelopes, response envelopes, and fulfillment records as defined in Section 9 and Section 10. Payload content within these envelopes is opaque to the transport.¶
This specification defines the protocol abstractly in terms of messages exchanged between roles. A transport binding maps these abstract messages onto a concrete network transport.¶
The initial transport binding is UDP. Control plane messages are exchanged as UDP datagrams between endpoints and registries. Data plane encrypted frames are exchanged as UDP datagrams between peers. Implementations are responsible for handling MTU constraints and chunking large payloads into multiple datagrams as needed.¶
The protocol does not rely on TCP semantics. It does not assume ordered delivery, connection state, or stream-oriented framing at the transport layer. Each protocol message is self-contained within its datagram.¶
Future transport bindings (for example, QUIC) may be defined in companion specifications. The protocol's message semantics are transport-independent; only the framing and delivery characteristics change with the binding.¶
Implementations using the UDP transport binding MUST conform to the guidelines in [RFC8085]. In particular:¶
The control plane (Section 4.1) is self-limiting: each discovery query produces at most one response, presence announcements are periodic with configurable intervals, and admission exchanges are bounded by session establishment rate. Deployments MUST ensure that control plane traffic does not constitute sustained high-rate uncontrolled UDP transmission.¶
The data plane (Section 4.2) carries application traffic within encrypted frames. Implementations that sustain high-rate data plane traffic MUST implement appropriate congestion control. CIRP does not define a congestion control algorithm; implementations MAY use any mechanism that provides appropriate congestion response, including rate limiting, application-level pacing, or integration with a congestion-controlled transport (such as QUIC in a future binding).¶
Implementations SHOULD implement per-destination rate limiting on control plane transmissions to prevent amplification. A registry that receives a high rate of discovery queries for a single capability SHOULD apply local rate limits rather than forwarding unbounded traffic to providers.¶
CIRP does not define a protocol-level flow control mechanism. Each endpoint manages its own resource consumption locally. Implementations SHOULD enforce local limits on:¶
Maximum inbound frame rate per session. Maximum encrypted frame size (bounded by the MTU of the underlying transport binding). Maximum concurrent sessions per endpoint.¶
If an endpoint's local capacity is exceeded, it SHOULD stop reading from the transport socket, allowing natural backpressure. The sending peer will observe increased loss (for UDP) or reduced throughput (for future congestion-controlled bindings) and adapt accordingly.¶
Sessions that exceed locally configured resource bounds MAY be terminated via the idle timeout mechanism (Section 8.7) or via an authenticated close frame.¶
Capabilities in CIRP are addressed using structured URIs that combine a hierarchical namespace with mandatory version information. This addressing scheme enables precise discovery, prevents semantic drift across protocol versions, and supports independent evolution of capabilities within distinct organizational namespaces.¶
A capability URI uses the "cap" scheme and has the following structure:¶
cap-uri = "cap:" path "/" version
path = segment 1*("." segment)
segment = ALPHA *(ALPHA / DIGIT / "-")
version = "v" major "." minor
major = 1*DIGIT
minor = 1*DIGIT
¶
The path component consists of dot-delimited segments forming a hierarchical namespace. The grammar requires at least two segments (one dot), establishing a minimum structure of namespace.action. Deeper hierarchies are permitted (e.g., "acme.robotics.arm.wave").¶
Segments MUST begin with an ASCII letter and MAY contain ASCII letters, digits, and hyphens. Segments are case-sensitive.¶
Examples of valid capability URIs:¶
cap:echo.ping/v1.0 cap:robot.wave/v1.0 cap:acme.robotics.arm.wave/v2.1 cap:org.medical.imaging.analyze/v1.0¶
Examples of invalid capability URIs:¶
cap:echo/v1.0 (single segment, no dot) cap:robot.wave (missing version) cap:robot.wave/1.0 (version missing "v" prefix) cap:123.test/v1.0 (segment begins with digit)¶
Every capability URI MUST include a version component in the format "v" followed by major.minor integers. Both the major and minor version numbers are REQUIRED.¶
Version matching in this specification uses exact semantics: a Provider advertising cap:x.y/v1.2 MUST NOT fulfill requests for cap:x.y/v1.3 unless the Provider explicitly advertises that version as well. Consumers MUST include the complete version in all discovery requests and invocation envelopes.¶
Compatible-range version matching (where a request for v1.2 could be fulfilled by a Provider advertising v1.3) is not defined in this specification. Future revisions MAY define version compatibility semantics.¶
For wire efficiency, capabilities are referenced in protocol messages by their hash rather than their full URI string. The capability hash is the SHA-256 digest of the capability's canonical name string.¶
The canonical name string is the path component of the capability URI including the version suffix, without the "cap:" scheme prefix. For the capability URI "cap:acme.robotics.arm.wave/v1.0", the canonical name string is the exact UTF-8 byte sequence of "acme.robotics.arm.wave/v1.0". The format is "{path}/v{major}.{minor}" where {path} is the dotted capability path and "v{major}.{minor}" follows the version grammar defined in Section 5.2.¶
The hash input is case-sensitive. No case folding, Unicode normalization, or whitespace removal is applied. The hash is computed over the exact UTF-8 byte sequence.¶
For indexed lookups, the cap64 index key is the first 8 bytes of the 32-byte SHA-256 digest, interpreted as a big-endian unsigned 64-bit integer.¶
The following test vectors are normative. Any implementation that produces a different digest for either input has a conformance error.¶
Vector 1: Input "system.echo/v1.0" produces SHA-256 e81664e525710d5a2d0cece876c00f10ed79dec5d6c775869c5723fff7018ca7 and cap64 0xe81664e525710d5a.¶
Vector 2: Input "acme.robotics.arm.wave/v1.0" produces SHA-256 386ed68f47809bde0663dc04a322766fd55aa9cdd41d7b6a1e147a90f9d96b85 and cap64 0x386ed68f47809bde.¶
Capability hashes are used in Authorization Requests (Section 7.2), ConnectTickets (Section 7.2.1), and presence advertisements. The full URI string is carried only in invocation envelopes (Section 9) where human readability and version information are required.¶
The prefix "cap:proto." is RESERVED for capabilities defined by this protocol and its companion specifications. Implementations MUST NOT advertise capabilities under the "proto" namespace unless those capabilities are defined in a CIRP specification document.¶
Namespace allocation and governance beyond the reserved prefix is a deployment concern. A registry for well-known capability namespaces may be established in a future revision of this specification. Deployments SHOULD use organizational domain names in reverse notation (e.g., "com.example.service.action") to minimize namespace collisions.¶
Discovery is the process by which a Consumer locates Providers of a given capability. The protocol defines a query-response mechanism mediated by Registries and a scoping model that controls capability visibility across organizational and trust boundaries.¶
Within an admitted scope, discovery results are unranked; however, Registries may apply policy controls including admission, scope enforcement, rate limiting, or denial of service. The protocol defines no preference ordering among eligible results. Visibility is governed by scope, not by policy ranking or commercial preference.¶
A Consumer discovers Providers by sending a FIND_EX_REQUEST (TLV type 0x76) to a Registry. The request is a fixed-size 64-byte payload:¶
The Consumer does not need to be authenticated to submit a discovery query, but the Registry MAY require the Consumer to be in an admitted state depending on deployment policy.¶
Future revisions of this specification may define additional discovery message types that carry parameters such as result limits or locality hints. These are out of scope for the initial protocol binding.¶
The Registry responds with a FIND_EX_RESPONSE (TLV type 0x77) containing at most one Provider entry. The response includes a status code indicating the outcome and, on success, the following fields:¶
The Registry uses the Provider's observed network address (the source address of the Provider's most recent presence message) as the authoritative locator. Self-reported addresses in presence messages are not used for routing, preventing stale or spoofed locators from directing traffic to incorrect endpoints.¶
Providers whose most recent presence beacon is older than a deployment-configured freshness threshold are excluded from query results. The freshness check uses the original beacon timestamp as recorded by the originating Registry, not timestamps assigned during inter-Registry synchronization. This prevents synchronized records from appearing artificially fresh.¶
When a Registry applies policy that modifies the result set (e.g., scope restrictions or tier-based limits), the response SHOULD include a Policy Receipt indicating the nature and reason for the modification. This supports the principle that policy enforcement is permitted but silent policy enforcement is not: consumers and diagnostic tools can observe how policies affect discovery results.¶
Capability advertisements carry a scope descriptor that controls their visibility during discovery. Scope enforcement is performed by the Registry during query processing, not by peer-side filtering logic. This ensures that scope is enforced consistently regardless of Consumer implementation.¶
Five scope levels are defined:¶
| Level | Value | Qualifier | Semantics |
|---|---|---|---|
| Local | 0x00 | None | Visible only to the advertising endpoint itself. Used for internal bookkeeping or credential-agent patterns where a capability serves only its owner. |
| Identity | 0x01 | target_eid (32 bytes) | Visible only to the endpoint identified by target_eid. Used for pre-arranged point-to-point capabilities. |
| Trust Domain | 0x02 | anchor_hash (32 bytes) | Visible to endpoints whose identity chain includes the trust anchor identified by anchor_hash. |
| Organization | 0x03 | anchor_hash (32 bytes) | Visible to endpoints within the organization identified by anchor_hash. Semantically equivalent to Trust Domain but conventionally used for organizational boundaries. |
| Global | 0x04 | None | Visible to all endpoints without restriction. |
The scope descriptor is carried in capability advertisements as a compact binary encoding:¶
Scope Descriptor +-------+------+----------------------------------------+ |Offset | Size | Field | +-------+------+----------------------------------------+ | 0 | 1 | scope_level | | 1 | 0/32 | qualifier (present for levels 0x01-0x03)| +-------+------+----------------------------------------+ Total size: Global (0x04): 1 byte Local (0x00): 1 byte Identity (0x01): 33 bytes (1 + 32-byte target EID) Trust Domain (0x02): 33 bytes (1 + 32-byte anchor hash) Organization (0x03): 33 bytes (1 + 32-byte anchor hash)¶
The anchor_hash for Trust Domain and Organization scopes is the SHA-256 hash of the trust anchor's Ed25519 public key. This allows scope enforcement without transmitting the full public key in every advertisement.¶
When processing a Discovery Query, the Registry evaluates the scope of each candidate Provider's capability advertisement against the querying Consumer's identity:¶
The mechanism by which a Registry determines membership in a trust domain is deployment-specific. Possible approaches include signed membership assertions from the trust anchor, pre-configured identity-to-domain mappings, or delegation chains. This specification defines the scope encoding and enforcement semantics but does not mandate a specific trust domain membership protocol.¶
In deployments with multiple Registries, Providers may register with different Registries. To provide a consistent view of available capabilities, Registries MAY synchronize presence information through a federation protocol.¶
When a Registry includes federated records in Discovery Responses, the freshness of those records MUST be evaluated using the original beacon timestamp as recorded by the Provider's home Registry, not the timestamp at which the record was received via federation. This prevents synchronized records from bypassing freshness filters.¶
The federation synchronization protocol is outside the scope of this specification and will be defined in a companion document.¶
A Provider that advertises multiple capabilities SHOULD emit a TLV_CAP_LIST frame (type 0x41) alongside each Presence announcement. A Provider that advertises multiple capabilities and does not emit TLV_CAP_LIST will not be discoverable by individual capability and will only be reachable via aggregate-hash discovery. The payload format is:¶
+--------+-----------------+------------------------------------------+ | 0x41 | Length (BE u16) | eid[32] | cap_hash_0[32] | ... | cap_N | +--------+-----------------+------------------------------------------+¶
The first 32 bytes of the payload are the Provider's Endpoint Identifier. The remainder is a sequence of 32-byte capability hashes, one per advertised capability. There is no explicit count field; the number of capabilities is derived from the payload length: cap_count = (payload_length - 32) / 32.¶
If the payload length is less than 32 bytes, or if (payload_length - 32) is not evenly divisible by 32, the frame is malformed and MUST be silently discarded per standard TLV processing rules.¶
TLV_CAP_LIST is a companion to the Presence announcement and MAY arrive in the same transport datagram or in a separate datagram. If a TLV_CAP_LIST arrives before any Presence record exists for the given EID, the Registry SHOULD hold it in a short-lived pending cache (RECOMMENDED 5-second TTL, bounded to a deployment-configurable maximum entry count) and apply it when the next Presence announcement for that EID arrives.¶
The Registry MUST maintain a per-capability discovery index that maps the first 8 bytes of each individual capability hash to sets of EIDs. When processing a Discovery Query, the Registry MUST check the per-capability index first. If results are found, those are returned. If the per-capability index contains no entries for the requested hash, the Registry MUST fall back to the aggregate capability index for backward compatibility with Providers that do not emit TLV_CAP_LIST.¶
The following functions are explicitly outside the scope of the discovery mechanism defined in this specification:¶
Capability name resolution. The protocol operates exclusively on capability hashes. Translation from human-readable names, aliases, partial strings, or natural-language descriptions to canonical capability identifiers is a client-side concern and is not defined by this specification. Implementations MAY provide resolution libraries or local catalogs, but these are not part of the protocol.¶
Capability enumeration. The protocol does not provide a mechanism for a Consumer to enumerate all capabilities available on the network. Discovery is query-by-hash only. A Consumer MUST know the hash of the capability it seeks. Registry-wide enumeration would create privacy and scalability concerns incompatible with the protocol's design goals.¶
Fuzzy or semantic matching. The Registry performs exact hash comparison only. Approximate matching, natural-language understanding, embedding-based similarity, and recommendation are application-layer concerns above the transport protocol. The protocol's hash-based discovery ensures deterministic, reproducible results regardless of implementation.¶
Capability ranking or recommendation. Within a given scope, discovery results are unranked. The protocol does not define ordering, scoring, or preferential treatment of Providers. Any ranking, prioritization, or recommendation of discovery results is a platform concern outside the scope of this specification.¶
Session establishment in CIRP follows a three-phase model that separates discovery, authorization, and cryptographic session setup. The critical architectural property is that the Registry participates only in the first two phases. Once authorization is complete, the Registry exits the protocol path entirely. All subsequent communication occurs on a peer-to-peer encrypted channel that the Registry can neither observe nor influence.¶
The three phases are:¶
This design ensures that connection throughput scales with the number of endpoints, not with Registry capacity. The Registry handles O(1) authorization per connection; it does not relay ongoing session traffic.¶
A Consumer MAY be aware of multiple Registries through configuration, DNS service records, or prior interaction. When multiple Registries are available, the Consumer SHOULD select the Registry with the lowest measured round-trip latency to minimize authorization delay.¶
Latency measurement is performed by sending a Probe message to each candidate Registry and measuring the time until a ProbeResponse is received. The Probe message contains an 8-byte nonce; the ProbeResponse echoes the nonce and MAY include the Registry's geographic locality hint. Registries MUST process Probe messages before any authentication or admission checks to ensure the measured latency reflects network conditions rather than processing overhead.¶
Probe messages are subject to a separate rate limit from other Registry interactions to prevent measurement traffic from interfering with authorization and discovery operations.¶
After receiving an Authorization Response with a ConnectTicket, the Consumer initiates a direct connection to the Provider. Before exchanging key material, the peers MUST negotiate a cryptographic suite.¶
Suite negotiation occurs as the first exchange on the peer-to-peer channel, before any key exchange messages. This keeps the Registry out of cryptographic decisions and avoids coupling Registry upgrades to cipher suite changes.¶
A suite identifier is a string token registered in the CIRP Crypto Suite Registry (see Section 12.1). Each suite identifier specifies the complete set of algorithms used for a session:¶
The following suite is mandatory to implement:¶
CIRP_X25519_ED25519_CHACHA20POLY1305_SHA256 Key agreement: X25519 [RFC7748] Authentication: Ed25519 [RFC8032] Symmetric encryption: ChaCha20-Poly1305 [RFC8439] Key derivation: HKDF-SHA-256 [RFC5869]¶
The following hybrid suite is defined for post-quantum transition:¶
CIRP_X25519MLKEM768_ED25519_CHACHA20POLY1305_SHA256
Key agreement: X25519 [RFC7748] combined with
ML-KEM-768 [FIPS203]
Authentication: Ed25519 [RFC8032]
Symmetric encryption: ChaCha20-Poly1305 [RFC8439]
Key derivation: HKDF-SHA-256 [RFC5869]
¶
Suite negotiation consists of two messages:¶
Upon receiving a SuiteOffer, the Provider:¶
Upon receiving a SuiteSelect, the Consumer:¶
After suite negotiation, the peers perform a key exchange to establish shared session keys. The key exchange protocol depends on the negotiated suite but follows a uniform structure.¶
For suites using X25519 as the sole key agreement algorithm, the key exchange proceeds as follows:¶
The Ed25519 signatures on the KeyExchange messages bind the ephemeral keys to the peers' long-term identities. An attacker who intercepts the ephemeral public keys cannot forge the signatures without possessing the peers' long-term private keys.¶
Ephemeral keys MUST be generated fresh for each session and MUST NOT be reused. This provides forward secrecy: compromise of a peer's long-term Ed25519 signing key does not expose the session keys of previously established sessions.¶
For suites combining X25519 with a post-quantum key encapsulation mechanism (such as ML-KEM-768 as specified in [FIPS203]), the key exchange produces two independent shared secrets that are combined via the key schedule.¶
The hybrid exchange proceeds as follows:¶
When operating in hybrid mode, both the classical and post-quantum key exchanges MUST succeed. If either exchange fails, session establishment MUST fail. An implementation MUST NOT fall back to classical-only key agreement when a hybrid suite has been negotiated. This prevents downgrade to classical-only security when both peers have agreed to hybrid protection.¶
Regardless of the negotiated suite, session keys are derived using HKDF [RFC5869] with SHA-256 as the hash function, following the extract-then-expand paradigm of [NIST-SP-800-56C]:¶
For classical suites:
ikm = classical_ss
For hybrid suites:
ikm = classical_ss || pq_ss
PRK = HKDF-Extract(salt=session_id, ikm)
key = HKDF-Expand(PRK, info, L=32)
where:
session_id = 16-byte session identifier
info = "cirp-hybrid-kx" || suite_id ||
consumer_eid || provider_eid
L = 32 (256 bits, for ChaCha20-Poly1305)
¶
The info string binds the derived key material to the session context and both peer identities. The suite_id is the ASCII-encoded suite identifier string as negotiated. The consumer_eid and provider_eid are the 32-byte EIDs of the respective peers.¶
Using the same KDF structure for both classical and hybrid suites simplifies implementation and allows the key derivation path to be verified independently of the key agreement mechanism.¶
Once session keys are derived, the peers communicate using authenticated encrypted frames. Each frame uses ChaCha20-Poly1305 [RFC8439] for authenticated encryption with associated data (AEAD).¶
The encrypted frame format is:¶
Encrypted Frame +-------+------+----------------------------------------+ |Offset | Size | Field | +-------+------+----------------------------------------+ | 0 | 4 | magic (0x41 0x49 0x43 0x46) | | 4 | 16 | session_id | | 20 | 8 | counter (monotonic, BE) | | 28 | 12 | nonce (ChaCha20-Poly1305) | | 40 | N | ciphertext | | 40+N | 16 | authentication_tag (Poly1305) | +-------+------+----------------------------------------+ Minimum frame size: 56 bytes (empty payload)¶
The counter field is a monotonically increasing 64-bit integer, incremented for each frame sent within a session. Receivers MUST reject frames with a counter value less than or equal to the highest counter previously accepted in the same session. This provides replay protection without requiring synchronized state beyond the highest seen counter.¶
The nonce is constructed deterministically from the counter and session key material. Implementations MUST NOT reuse a nonce with the same key.¶
The protocol imposes no semantic limit on payload size within encrypted frames. Implementations MAY enforce practical limits based on the underlying transport binding. For UDP transport, implementations typically target application payloads that fit within common path MTU limits and handle larger payloads through fragmentation and reassembly at the session layer.¶
The ciphertext is opaque to the transport layer. It carries application data (including intent invocation envelopes as defined in Section 9) without interpretation, canonicalization, or transformation by the transport.¶
Prior to establishing a session, the Provider MUST verify that the capability_hash field of the presented ConnectTicket identifies a capability that the Provider actively advertises. Formally, the Provider MUST confirm that ticket.capability_hash is a member of the set of per-capability hashes for which the Provider maintains current presence advertisements. If the capability_hash does not match any actively advertised capability, the Provider MUST reject the connection attempt with reason CapabilityNotServed (0x04).¶
Upon successful session establishment, the session MUST retain the authorized capability_hash as immutable session state. The capability binding is fixed at session creation and MUST NOT change for the lifetime of the session. Implementations MUST NOT permit rebinding of a session to a different capability after establishment.¶
The bound capability_hash MUST be available to the application layer for the purposes of session routing and audit. Providers serving multiple capabilities MUST use this binding to dispatch inbound sessions to the appropriate capability handler.¶
The capability match verification set and the per-capability advertisement set MUST be maintained as a single atomic unit. If these sets can diverge, a ticket issued for a discovered capability could be rejected after discovery, or a ticket for a withdrawn capability could be accepted.¶
A CIRP session transitions through five states: IDLE, DISCOVERY, AUTHORIZED, ESTABLISHED, and CLOSED. Once ESTABLISHED, the session remains active until one of the following conditions is met:¶
Idle Timeout. If no encrypted frame (as defined in Section 7.5) is received from the remote peer within the locally configured inactivity window, the endpoint MUST transition the session to CLOSED and release all associated resources. The idle timeout is the normative teardown mechanism for CIRP sessions.¶
Implementations SHOULD use a default idle timeout of 120 seconds. Deployments MAY configure smaller values for resource-constrained or latency-sensitive environments. The idle timeout is a local configuration parameter; it is not negotiated between peers and need not be symmetric. Each endpoint independently manages its own session lifetime.¶
Authenticated Close. An endpoint MAY send an encrypted control frame (type 0x01) within the AEAD-protected channel to signal intentional session termination. This frame carries a CloseReason code: 0x00 Normal (orderly shutdown), 0x01 GoingAway (endpoint shutting down), 0x02 PolicyViolation (peer violated session constraints), 0x03 InternalError (unrecoverable local failure).¶
Receipt of an authenticated close frame SHOULD cause the local endpoint to transition the session to CLOSED. The authenticated close is a courtesy notification; the idle timeout provides the normative guarantee that abandoned sessions do not persist indefinitely.¶
Unauthenticated Close Prohibition. Implementations MUST NOT transition session state based on receipt of any unauthenticated message. In particular, plaintext frames carrying session identifiers MUST be silently discarded without affecting session state. Any session teardown signal that is not protected by the session's AEAD keys is indistinguishable from a spoofed packet and MUST be ignored.¶
Session Identifier Uniqueness. Each session MUST use a unique session_id generated from a cryptographically secure random source. A session_id MUST NOT be reused across sessions between the same pair of endpoints. Implementations SHOULD use 128-bit (16-octet) random values.¶
Key Material Erasure. Upon transition to CLOSED, implementations MUST erase all ephemeral key material associated with the session, including X25519 private keys, derived session encryption keys, and AEAD nonce state. Implementations SHOULD use explicit memory zeroization rather than relying on garbage collection or deallocation.¶
The per-capability discovery mechanism (TLV_CAP_LIST, type 0x41) is designed for incremental deployment with no flag day. Implementations MUST NOT require coordinated upgrades. Each side may upgrade independently. Full per-capability discovery activates when both Provider and Registry support TLV_CAP_LIST.¶
Pre-0x41 Provider with pre-0x41 Registry: discovery operates via the aggregate capability index only. Single-capability Providers are discoverable; multi-capability Providers require exact aggregate hash match.¶
Pre-0x41 Provider with 0x41-aware Registry: the Provider does not emit TLV_CAP_LIST. The Registry receives no per-capability hashes. FIND_EX queries fall back to the aggregate index. No degradation.¶
0x41-aware Provider with pre-0x41 Registry: the Provider emits TLV_CAP_LIST (0x41). The Registry does not recognize type 0x41 and silently ignores it per standard TLV processing rules. Discovery continues via the aggregate index. No error, no degradation.¶
0x41-aware Provider with 0x41-aware Registry: the Provider emits TLV_CAP_LIST alongside Presence announcements. The Registry indexes each individual capability hash. Multi-capability Providers are fully discoverable by any single capability they advertise.¶
The changes described in this revision introduce no modifications to existing wire formats. The Presence beacon (TLV 0x35) format is unchanged. The ConnectTicket wire format (272 octets) is unchanged. The FIND_EX_REQUEST (TLV 0x76) and FIND_EX_RESPONSE (TLV 0x77) formats are unchanged.¶
TLV_CAP_LIST (type 0x41) is a new, additive TLV frame type. It does not replace or modify any existing frame. Per the TLV forward-compatibility rule, receivers that do not recognize type 0x41 silently ignore the frame.¶
The encrypted frame format (Section 7.5) is unchanged. The addition of an authenticated close control frame (type 0x01 within the AEAD-protected channel) uses the existing encrypted frame envelope and does not modify the frame header.¶
No existing TLV type codes have been reassigned or removed. Implementations conforming to the previous revision will interoperate with implementations conforming to this revision without modification.¶
CIRP uses distinct framing for control plane and data plane messages to enable demultiplexing on shared transport sockets.¶
Control plane messages between endpoints and Registries use a type-length-value (TLV) envelope:¶
Control Plane TLV Envelope +-------+------+----------------------------------------+ |Offset | Size | Field | +-------+------+----------------------------------------+ | 0 | 1 | message_type | | 1 | 2 | payload_length (BE) | | 3 | var | payload | +-------+------+----------------------------------------+¶
The message_type field identifies the control plane operation (e.g., presence announcement, discovery query, authorization request). The payload_length field is a 16-bit big-endian unsigned integer specifying the number of bytes following the header.¶
Data plane messages between peers use magic-byte prefixed frames. Two frame types are defined:¶
Receivers distinguish control plane from data plane messages by inspecting the first byte: TLV type values occupy a different range from the ASCII 'A' (0x41) that begins both data plane magic sequences.¶
The framing layer provides the following guarantees:¶
Intent invocation is the mechanism by which a Consumer requests execution of a capability and receives a fulfillment response from a Provider. Invocation messages are carried within the encrypted peer-to-peer session established in Section 7. The transport layer does not interpret, validate, or transform the payload contents of invocations or fulfillments.¶
Invocation envelopes are encoded using CBOR [RFC8949] with deterministic encoding as specified in Section 4.2 of that document. Deterministic encoding ensures that the same logical content always produces identical byte sequences, which is essential for stable signatures and hash computation. CBOR map keys are encoded as unsigned integers for compactness.¶
The invocation request envelope contains the following fields, encoded as a CBOR map with integer keys:¶
| Key | Field | CBOR Type | Size | Description |
|---|---|---|---|---|
| 1 | invocation_id | bstr | 16 | Unique identifier for this invocation, generated randomly by the Consumer. |
| 2 | capability_uri | tstr | variable | Full capability URI including version (e.g., "cap:robot.wave/v1.0"). This is the human-readable form; the hash used during discovery can be recomputed from this value. |
| 3 | payload_type | tstr | variable | Identifier for the payload encoding. This MAY be a MIME type or an application-defined type string. The protocol does not interpret this value. |
| 4 | payload | bstr | variable | Opaque payload bytes. The protocol does not parse, canonicalize, or transform this field. Content interpretation is entirely the responsibility of the Consumer and Provider. |
| 5 | consumer_eid | bstr | 32 | Consumer's Endpoint Identifier. |
| 6 | consumer_send_ts | uint | 8 | Consumer's local send timestamp, unsigned 64-bit milliseconds since Unix epoch. |
| 7 | prev_invocation_hash | bstr | 32 | SHA-256 hash of the previous invocation envelope in this Consumer-Provider relationship. Set to 32 zero bytes for the first invocation. See Section 10.3. |
| 8 | consumer_signature | bstr | 64 | Ed25519 signature computed over the deterministic CBOR encoding of fields 1 through 7 (all fields except the signature itself). |
The Consumer MUST generate the invocation_id using a cryptographically secure random number generator. Invocation identifiers are used for correlation between requests, responses, error frames, and fulfillment records.¶
The signature is computed over the canonical CBOR encoding of a map containing keys 1 through 7 with their values. The Consumer uses its Ed25519 signing key (the private key corresponding to consumer_eid) to produce the signature. This binds the invocation content to the Consumer's identity and prevents tampering in transit.¶
The Provider responds to an invocation with a fulfillment response encoded as a CBOR map:¶
| Key | Field | CBOR Type | Size | Description |
|---|---|---|---|---|
| 1 | invocation_id | bstr | 16 | Copied from the request for correlation. |
| 2 | fulfillment_status | uint | 1 | Status of the fulfillment: 0x00 for success, 0x01 for partial, 0x02 for application error (details in payload). |
| 3 | payload_type | tstr | variable | Identifier for the response payload encoding. |
| 4 | payload | bstr | variable | Opaque response payload. Not parsed by the protocol. |
| 5 | provider_eid | bstr | 32 | Provider's Endpoint Identifier. |
| 6 | provider_recv_ts | uint | 8 | Provider's local timestamp when the request was received. |
| 7 | provider_send_ts | uint | 8 | Provider's local timestamp when the response was sent. |
| 8 | request_hash | bstr | 32 | SHA-256 hash of the complete request envelope (all bytes including the Consumer's signature). Binds the response to a specific request. |
| 9 | provider_signature | bstr | 64 | Ed25519 signature over the deterministic CBOR encoding of fields 1 through 8. |
The Provider MUST include the request_hash computed over the entire request envelope as received. This cryptographically binds the response to the specific request, preventing a malicious party from associating a valid response with a different request.¶
When the fulfillment_status is 0x02 (application error), the payload field carries application-specific error information. The protocol does not define the structure of application-level errors; they are opaque bytes interpreted solely by the Consumer and Provider.¶
CIRP distinguishes between protocol-level errors and application-level errors. Application-level errors are carried inside the response payload (fulfillment_status 0x02) and are opaque to the protocol. Protocol-level errors indicate failures in session establishment, authorization, or transport that prevent an invocation from reaching the Provider or a response from reaching the Consumer.¶
Protocol-level errors are conveyed in signed error frames. Signing error frames prevents an active network attacker from injecting spurious errors to disrupt communication.¶
An error frame is encoded as a CBOR map:¶
| Key | Field | CBOR Type | Description |
|---|---|---|---|
| 1 | invocation_id | bstr | Correlation identifier from the request, if available. Set to 16 zero bytes if the error is not associated with a specific invocation. |
| 2 | error_code | uint | Numeric error code from the CIRP Error Code registry. |
| 3 | error_detail | tstr | Optional human-readable description. Implementations MUST NOT rely on the content of this field for programmatic error handling. |
| 4 | error_origin | uint | Indicates which component generated the error: 0x01 for Registry (authorization phase), 0x02 for Provider (invocation phase), 0x03 for transport (timeout or connection failure). |
| 5 | originator_eid | bstr | EID of the entity that generated the error. |
| 6 | signature | bstr | Ed25519 signature over fields 1 through 5. |
The following error codes are defined. Additional codes may be registered in the CIRP Protocol Parameters Registry (Section 12.3).¶
| Code | Name | Description |
|---|---|---|
| 0x01 | CAPABILITY_NOT_FOUND | No Provider advertises the requested capability. |
| 0x02 | PROVIDER_UNAVAILABLE | The Provider is not reachable or has become unresponsive. |
| 0x03 | AUTHORIZATION_EXPIRED | The ConnectTicket has expired. |
| 0x04 | TICKET_INVALID | The ConnectTicket failed validation. |
| 0x05 | SUITE_MISMATCH | No common cryptographic suite exists between the peers. |
| 0x06 | RATE_LIMITED | The request exceeds the Consumer's rate allocation. |
| 0x07 | SCOPE_DENIED | The Consumer's identity does not satisfy the capability's scope requirements. |
| 0x08 | TIMEOUT | The operation exceeded the applicable time limit. |
| 0x09 | INTERNAL_ERROR | An unspecified internal error occurred. |
CIRP provides a mutually attested record of each invocation-fulfillment exchange. This record, called a fulfillment receipt, is constructed cooperatively by the Provider and Consumer through a two-phase signing ceremony. The receipt establishes a tamper-evident, non-repudiable audit trail without relying on a trusted third party or synchronized clocks.¶
The fulfillment record is encoded as a CBOR map using deterministic encoding ([RFC8949], Section 4.2). The record is constructed in two phases:¶
After processing an invocation and generating a response, the Provider constructs a partial fulfillment record containing the following fields:¶
| Key | Field | CBOR Type | Description |
|---|---|---|---|
| 1 | invocation_id | bstr (16) | Identifier of the invocation this receipt covers. |
| 2 | request_hash | bstr (32) | SHA-256 hash of the complete request envelope as received. |
| 3 | response_hash | bstr (32) | SHA-256 hash of the complete response envelope as sent. |
| 4 | provider_recv_ts | uint | Provider's local clock reading when the request was received (milliseconds since epoch). |
| 5 | provider_send_ts | uint | Provider's local clock reading when the response was sent. |
| 6 | provider_eid | bstr (32) | Provider's Endpoint Identifier. |
| 7 | provider_signature | bstr (64) | Ed25519 signature over the deterministic CBOR encoding of fields 1 through 6. |
The Provider sends this partial record alongside the response envelope. The Provider's signature attests that the Provider processed the identified request and produced the identified response at the stated times.¶
Upon receiving the response and the Provider's partial record, the Consumer appends additional fields and produces the final fulfillment record:¶
| Key | Field | CBOR Type | Description |
|---|---|---|---|
| 1-7 | (Provider fields) | (as above) | All fields from Phase 1 including the Provider's signature. |
| 8 | consumer_send_ts | uint | Consumer's local clock reading when the request was sent. |
| 9 | consumer_recv_ts | uint | Consumer's local clock reading when the response was received. |
| 10 | consumer_eid | bstr (32) | Consumer's Endpoint Identifier. |
| 11 | consumer_signature | bstr (64) | Ed25519 signature over the deterministic CBOR encoding of fields 1 through 10 (including the Provider's signature). |
The Consumer's signature covers the entire record including the Provider's signature at field 7. This creates a nested attestation: the Consumer attests that it received the Provider's signed partial record and that the Consumer's own timestamps are accurate. Neither party can tamper with the other's attested fields without invalidating the corresponding signature.¶
A third party verifying a fulfillment record performs the following checks:¶
If both signatures verify, the receipt cryptographically establishes that both parties participated in the exchange and attested to its contents.¶
The fulfillment record contains four timestamps representing the complete round-trip of an invocation:¶
Consumer Provider | | |-- consumer_send_ts | | (request sent) | | | | provider_recv_ts -- | (request received) | | | | provider_send_ts -- | (response sent) | | | |-- consumer_recv_ts | | (response received)| | |¶
Timestamps are encoded as unsigned 64-bit integers representing milliseconds since the Unix epoch (1970-01-01T00:00:00Z).¶
Clock synchronization between Consumer and Provider is NOT assumed. Each party records timestamps using its own local clock. The timestamp model is designed for relative timing analysis rather than absolute time agreement:¶
The consumer_send_ts and provider_send_ts fields are REQUIRED (MUST be present). The provider_recv_ts and consumer_recv_ts fields SHOULD be present; omitting them degrades the usefulness of the receipt for latency analysis but does not invalidate the record.¶
Implementations MUST NOT reject receipts solely because timestamps appear inconsistent (e.g., provider_recv_ts earlier than consumer_send_ts). Such inconsistency indicates clock skew, not necessarily fraud. Implementations MAY flag such records for review.¶
Each invocation request envelope includes a prev_invocation_hash field (see Section 9.1) that references the SHA-256 hash of the immediately preceding request envelope in the same Consumer-Provider relationship. For the first invocation between a given Consumer and Provider, this field is set to 32 zero bytes.¶
This creates a hash chain that provides the following properties:¶
Hash chains are maintained by the Consumer. A Consumer MUST track the hash of its most recent request envelope for each active Provider relationship. If a Consumer loses this state (e.g., due to a restart), it SHOULD set prev_invocation_hash to 32 zero bytes, effectively starting a new chain. The Provider MAY note chain resets for audit purposes but MUST NOT reject invocations solely because the hash chain was reset.¶
This section analyzes the security properties of CIRP under a threat model that assumes an active network attacker, potentially compromised Registries, and potentially compromised peer endpoints. The analysis addresses each threat class and identifies the cryptographic mechanisms that mitigate it.¶
The protocol is designed to resist the following adversaries:¶
Every endpoint in CIRP is identified by its Ed25519 [RFC8032] public key. The Endpoint Identifier (EID) is the public key itself, not a hash or derivative. This identity model has several consequences:¶
During session establishment, mutual authentication is achieved through the following chain: the Consumer proves identity by signing the SuiteOffer (which includes the ConnectTicket naming the Consumer's EID), and the Provider proves identity by signing the SuiteSelect and KeyExchange messages using the key corresponding to the EID named in the ticket's provider_eid field. Both parties verify these signatures before proceeding to key exchange.¶
Registries occupy a semi-trusted role. The following analysis enumerates what a Registry can and cannot do, and provides cryptographic justification for each boundary.¶
The ConnectTicket (Section 7.2.1) is the authorization boundary between the control plane and the data plane. Its security depends on several properties:¶
Each session uses freshly generated ephemeral X25519 keypairs for key exchange. Session keys are derived from the ephemeral shared secret, not from the peers' long-term Ed25519 keys. Compromise of a peer's long-term signing key allows an attacker to impersonate that peer in future sessions, but it does not expose the session keys of previously established sessions because the ephemeral X25519 private keys are discarded after key derivation.¶
Long-term Ed25519 keys are used solely for authentication (signing key exchange messages and protocol artifacts), not for key agreement. The key agreement function (X25519) operates on independent ephemeral key material.¶
Replay attacks are addressed at multiple layers:¶
Two mechanisms prevent cryptographic downgrade attacks:¶
CIRP addresses the threat of harvest-now-decrypt-later attacks through its cryptographic agility framework and hybrid key exchange construction.¶
The protocol supports hybrid post-quantum key establishment via negotiated cipher suites. In hybrid mode, session keys are derived from both a classical X25519 shared secret and a post-quantum shared secret (e.g., from ML-KEM-768 as specified in [FIPS203]), combined through HKDF (Section 7.4.3). This construction ensures that the session key is at least as strong as the stronger of the two components: even if the post-quantum algorithm is later found to be weak, the classical component still provides security, and vice versa.¶
The suite negotiation mechanism (Section 7.3) allows new cryptographic suites to be deployed without protocol revision. As post-quantum algorithms mature and new key encapsulation mechanisms are standardized, they can be registered in the CIRP Crypto Suite Registry and adopted by implementations through normal suite negotiation.¶
Implementations MUST support suite negotiation as defined in Section 7.3. Implementations MUST support at least the mandatory classical suite. Implementations SHOULD support at least one hybrid post-quantum suite. Future revisions of this specification may strengthen the hybrid requirement to MUST as post-quantum algorithms achieve broader deployment maturity.¶
Invocation envelopes and response envelopes are signed by the originating party using Ed25519. The signature covers the deterministic CBOR encoding of all fields except the signature itself (Section 9.1, Section 9.2). This provides:¶
The response envelope includes a request_hash field that binds the response to a specific request. This prevents an attacker from associating a legitimate response with a different request.¶
Fulfillment records extend these properties through cooperative dual-signing (Section 10.1), creating a mutually attested audit trail that neither party can unilaterally repudiate.¶
Protocol-level error frames are signed by the originating entity (Section 9.3). This prevents an active network attacker from injecting spurious error messages to disrupt communication. A receiver MUST verify the signature on an error frame before acting on it. Unsigned or incorrectly signed error frames MUST be discarded.¶
Capability visibility scoping (Section 6.3) is enforced by the Registry during discovery. Because scope enforcement depends on the Registry correctly evaluating scope rules, a compromised Registry could bypass scope restrictions and expose capabilities intended to be private.¶
Deployments with strict confidentiality requirements for capability visibility SHOULD use dedicated Registries operated within the trust domain. Capability scoping provides defense in depth but does not replace network-level access controls where confidentiality of capability existence is critical.¶
Several protocol elements are susceptible to denial of service attacks:¶
The protocol relies on timestamp comparison for ConnectTicket expiration checking. Clock skew between the Registry (which sets issued_at and expires_at) and the Provider (which checks expiration) may cause valid tickets to be incorrectly rejected or expired tickets to be incorrectly accepted.¶
Implementations MUST apply bounded clock skew tolerance as defined in Section 7.2.1. The RECOMMENDED 10-second leeway accommodates typical NTP drift across cloud regions (2-5 seconds) with margin. The future-rejection rule (rejecting tickets where issued_at exceeds now + leeway) prevents acceptance of tickets with severely desynchronized or maliciously future-dated issuance timestamps. Without this check, a compromised Registry could issue tickets with far-future issued_at values that would remain valid indefinitely under expiry-only validation. Deployments operating across geographically distributed infrastructure SHOULD ensure that Registry and Provider clocks are synchronized to within a few seconds using NTP or equivalent mechanisms.¶
Fulfillment record timestamps (Section 10.2) explicitly do not assume clock synchronization between Consumer and Provider. Each party records timestamps on its own clock. The timestamp model is designed for single-clock interval analysis (processing time, round-trip time) rather than cross-clock absolute time comparisons.¶
The prohibition on unauthenticated close (Section 7.7) eliminates a denial-of-service vector present in protocols that permit unsigned session teardown. An on-path attacker who observes a session_id during session establishment cannot forge a teardown message, because all state-changing messages after session establishment are protected by AEAD encryption with keys derived from the ephemeral key exchange.¶
The idle timeout mechanism ensures that sessions are eventually reclaimed even if both endpoints lose connectivity simultaneously or if one endpoint crashes without sending an authenticated close. The combination of authenticated close (best-effort notification) and idle timeout (guaranteed reclamation) provides both promptness and reliability.¶
Implementations MUST erase ephemeral key material on session close to preserve forward secrecy. An attacker who later compromises an endpoint's long-term signing key MUST NOT be able to derive past session keys.¶
The FIND_EX response envelope, including the Provider's RLOC (routing locator), is not independently signed. An active attacker between Consumer and Registry could modify the RLOC to redirect the Consumer to a different network address. However, the attacker cannot complete the subsequent key exchange because it does not possess the Provider's private key. This is a misdirection-for-DoS vector, not a confidentiality or integrity compromise.¶
Deployments requiring authenticated locator distribution SHOULD use a transport binding that provides channel integrity (e.g., DTLS or QUIC).¶
This document requests the creation of the following registries upon publication.¶
IANA is requested to create a "CIRP Crypto Suite Registry" with the following initial entries. New entries require Specification Required registration policy.¶
| Suite Identifier | Status |
|---|---|
| CIRP_X25519_ED25519_CHACHA20POLY1305_SHA256 | Mandatory |
| CIRP_X25519MLKEM768_ED25519_CHACHA20POLY1305_SHA256 | Recommended |
Each suite identifier encodes its component algorithms in the name: key agreement, authentication, AEAD, and KDF, separated by underscores. The algorithms for each initial entry are specified in Section 7.3.1.¶
Suite identifiers are ASCII strings. The naming convention concatenates the key agreement, authentication, AEAD, and KDF algorithm names separated by underscores, prefixed with "CIRP_".¶
The ML-KEM-768 algorithm in the hybrid suite is as specified in [FIPS203].¶
IANA is requested to register the "cap" URI scheme in the "Uniform Resource Identifier (URI) Schemes" registry per [RFC7595].¶
IANA is requested to create a "CIRP Protocol Parameters" registry with the following sub-registries. New entries in each sub-registry require Specification Required registration policy.¶
Initial entries are as defined in Section 9.3.1. The registry contains: code (uint8), name (string), and description (string).¶
Error codes are scoped to their enclosing TLV message type. Identical numeric values in different message types carry different semantics (e.g., 0x01 is TicketExpired in DirectAck but CapabilityNotFound in FindExStatus). Implementations MUST interpret error codes in the context of the message type that carries them. Four allocation ranges are defined: 0x00-0x3F for protocol-defined codes, 0x40-0xBF for profile-defined codes, 0xC0-0xFE for private use, and 0xFF reserved for future use.¶
Initial entries are the five scope levels defined in Section 6.3.1. The registry contains: value (uint8), name (string), qualifier size (uint8), and description (string).¶
This sub-registry tracks control plane TLV message types and data plane magic-byte prefixes. Initial entries include the message types referenced in Section 8.¶
A compliance agent advertises three capabilities: compliance.assess/v1.0, compliance.report/v1.0, and compliance.audit/v1.0. The agent computes per-capability hashes:¶
cap_hash_1 = SHA-256("compliance.assess/v1.0")
cap_hash_2 = SHA-256("compliance.report/v1.0")
cap_hash_3 = SHA-256("compliance.audit/v1.0")
sorted = sort(["compliance.assess/v1.0",
"compliance.audit/v1.0",
"compliance.report/v1.0"])
caps_hash = SHA-256(join(sorted, "\n"))
¶
The agent sends a single UDP datagram containing two coalesced TLVs:¶
+------+--------+------------------------------------------+ | 0x35 | len | Presence beacon (v2) | | | | eid[32] + flags[1] + rloc[7] + | | | | ttl[4] + caps_hash[32] + vk[32] + | | | | signature[64] + token[74]? | +------+--------+------------------------------------------+ | 0x41 | len | TLV_CAP_LIST | | | | eid[32] + | | | | cap_hash_1[32] + | | | | cap_hash_2[32] + | | | | cap_hash_3[32] | +------+--------+------------------------------------------+¶
Total: 3-byte TLV header + presence payload + 3-byte TLV header + 128-byte cap list payload. Both TLVs fit within the 1400-byte MTU budget. The Registry processes both TLVs: the Presence beacon updates the aggregate index; the cap list creates three entries in the per-capability index.¶
A Consumer agent needs compliance reporting. It computes:¶
query_hash = SHA-256("compliance.report/v1.0")
¶
The Consumer sends FIND_EX_REQUEST (TLV 0x76):¶
+------+--------+------------------------------------------+ | 0x76 | 0x0040 | capability_hash[32] + initiator_eid[32] | +------+--------+------------------------------------------+¶
The Registry checks the per-capability index for query_hash. It finds the compliance agent registered in Example B.1, because cap_hash_2 from the agent's TLV_CAP_LIST matches query_hash exactly. The Registry issues a FIND_EX_RESPONSE (TLV 0x77) containing status Success (0x00), the compliance agent's EID and RLOC, and a ConnectTicket (272 octets) binding initiator_eid + responder_eid + query_hash.¶
A compliance agent advertises three capabilities. An attacker obtains a valid ConnectTicket where capability_hash = SHA-256("compliance.report/v1.0") and attempts to misuse it in two ways.¶
Scenario A: Ticket tampering. The attacker modifies the ticket's capability_hash field to SHA-256("compliance.audit/v1.0") before presenting the DirectProbe. The Provider verifies the ticket's Ed25519 signature. Because capability_hash is within the signed preimage (octets 0-207), the modification invalidates the signature. The Provider silently drops the probe per Phase 2 (cryptographic validation).¶
Scenario B: Session misuse. The attacker presents the unmodified ticket and successfully establishes a session. The session is bound to SHA-256("compliance.report/v1.0") at establishment time per Section 7.6. This binding is immutable. The Provider dispatches this session to the compliance.report handler. The attacker cannot reach a different capability handler through this session regardless of payload content.¶
An agent running a pre-0x41 SDK sends a Presence beacon with caps_hash but does NOT emit TLV_CAP_LIST. The agent advertises a single capability: system.echo/v1.0.¶
A Consumer queries FIND_EX with:¶
query_hash = SHA-256("system.echo/v1.0")
¶
The Registry checks the per-capability index. No entry exists (agent did not send TLV_CAP_LIST). The Registry falls back to the aggregate index. For a single-capability agent, caps_hash equals the individual cap_hash, so the aggregate lookup succeeds. The Consumer receives a valid FIND_EX_RESPONSE and proceeds normally. The legacy agent is fully discoverable without any upgrade.¶