| Internet-Draft | QUIP | May 2026 |
| Mututi | Expires 13 November 2026 | [Page] |
This document specifies QUIP (QUIC Identity Protocol), a federated application protocol providing portable cryptographic identity, verifiable server trust, deterministic state synchronization, and built-in accountability. QUIP runs over QUIC (RFC 9000) and uses a strict deterministic CBOR profile (QUIP-CBOR). Three conformance profiles are defined: Basic (messaging), Documents (content addressing), and Media (real-time transport). The protocol enables users to own a portable NodeId independent of service providers, servers to authenticate via DANE+DNSSEC with deployable fallback modes, and peers to detect and throttle misbehavior through signed violation receipts propagated via gossip.¶
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 13 November 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.¶
QUIP defines a federation-native protocol that ensures:¶
QUIP operates directly over QUIC [RFC9000] and eliminates reliance on HTTP-based federation layers.¶
The following example demonstrates a complete QUIP flow:¶
Alice (NodeId A) → a.com → b.com → Bob (NodeId B) 1. Identity Setup • a.com issues primary attestation binding user@a.com to NodeId A • Requires subject signature (proof of possession) 2. Sending a Message • Alice signs message with private key A • a.com forwards to b.com over QUIC + DANE • b.com verifies signature + attestation + policies • Bob receives message 3. Accountability • If a.com misbehaves, b.com creates signed violation receipt • Receipt gossips to federation • Automatic throttling after independent witness threshold¶
QUIP does NOT guarantee:¶
Note on categorization: The items above mix design choices (anonymity, metadata confidentiality) with explicit security limitations (collusion resistance, Byzantine consensus). All are intentional non-goals of the protocol.¶
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.¶
NodeIdGenesis NodeIdAttestationPrimary attestationuser@domain address to a NodeId¶
Vector clockGossipViolation receiptProfileQUIP connections SHALL be in one of the following states:¶
INITDISCOVERINGCONNECTINGHANDSHAKINGSYNCINGACTIVEDEGRADEDREVOKEDCLOSEDThe following transitions are normative:¶
| From | To | Trigger | Required Action |
|---|---|---|---|
| INIT | DISCOVERING | Application requests connection | Perform DNS SRV/TXT lookup |
| DISCOVERING | CONNECTING | DNS resolution succeeds | Initiate QUIC handshake |
| CONNECTING | HANDSHAKING | QUIC connection established | Send QUIP handshake on stream 0 |
| HANDSHAKING | SYNCING | Handshake complete, profiles compatible | Begin gossip sync on stream 1 |
| HANDSHAKING | CLOSED | Profile mismatch or handshake error | Send error, close connection |
| SYNCING | ACTIVE | Initial sync complete | Normal operation begins |
| SYNCING | CLOSED | Sync timeout or unrecoverable error | Send error, close connection |
| ACTIVE | DEGRADED | Resource exhaustion or policy violation | Reduce functionality |
| ACTIVE | REVOKED | Receipt of valid revocation attesting this peer | Terminate all active streams |
| ACTIVE | CLOSED | Connection loss or explicit close | Clean up state |
| REVOKED | CLOSED | Any | Final cleanup |
| DEGRADED | ACTIVE | Resource recovery | Resume normal operation |
State transitions not listed above are not permitted and MUST cause a connection error (Section 17.2 code 17: PROTOCOL_VIOLATION).¶
Implementations MUST enforce:¶
Layered model (bottom to top):¶
Every user has a NodeId — an Ed25519 public key (32 bytes). The corresponding private key is never disclosed to any domain or third party. NodeIds are encoded as raw byte strings in CBOR.¶
All attestations are signed CBOR objects.¶
The subject signs the following QUIP-CBOR array:¶
[ "QUIP-ATTESTATION-SUBJECT-V1", type, ; string subject, ; NodeId or address issuer, ; domain or NodeId [notBefore, notAfter] ; Unix timestamps (seconds) ]¶
The issuer signs the following QUIP-CBOR array:¶
[ "QUIP-ATTESTATION-ISSUER-V1", type, subject, issuer, [notBefore, notAfter], subject_signature ; 64 bytes ]¶
The complete attestation on the wire is:¶
tagged(65536, [ "primary_binding", ; discriminator type, subject, issuer, [notBefore, notAfter], subject_signature, issuer_signature ])¶
tagged(65536, [ "key_rotation", old_NodeId, ; 32 bytes new_NodeId, ; 32 bytes timestamp, ; Unix milliseconds (int64) signature ; 64 bytes ])¶
Signature computation:¶
signature = Ed25519_sign(
old_private_key,
"QUIP-ROTATION-V1" || QUIP-CBOR([
"key_rotation",
old_NodeId,
new_NodeId,
timestamp
])
)
¶
Rotation validation rules: Receivers MUST reject:¶
The Genesis NodeId is the oldest known NodeId in a rotation chain.¶
First message rule: If a receiver encounters a NodeId with no prior state, and the message is signed by a key that is not clearly the genesis, the sender MUST include the full rotation chain. Failure results in error KEY_ROTATION_CHAIN_MISSING (Section 17.2 code 15).¶
The identity_trust_mode bitmask is defined as:¶
| Bit | Name | Description |
|---|---|---|
| 0 | SIMPLE | Accept primary attestations from any domain |
| 1 | VERIFIED | Require attestations from certified providers (Section 7) |
| 2-15 | Reserved | Reserved for future use |
Negotiation: The effective trust mode is the bitwise AND of local and remote modes. If the result has no bits set, the connection proceeds with the lowest common mode (SIMPLE) and MUST log a warning.¶
Downgrade behavior: VERIFIED mode MUST NOT downgrade to SIMPLE without explicit operator configuration. Any downgrade MUST be logged.¶
| Mode | Requirement | Use Case |
|---|---|---|
| COMPAT (default) | Web PKI + SHOULD use DANE if available | General deployment |
| STRICT (optional) | DNSSEC + DANE REQUIRED | High-security environments |
| LEGACY (deprecated) | Web PKI only | Legacy transition |
A witness domain qualifies as independent for violation receipt validation if ALL conditions hold:¶
Additional weighting (SHOULD): Implementations SHOULD also consider distinct ASN (Autonomous System Number), distinct DNSSEC KSK (Key Signing Key), historical trust scoring based on past witness accuracy, and observed federation longevity (minimum 30 days active).¶
After TLS handshake completion, the client MUST verify that the server's presented certificate and DANE TLSA record (if applicable) are consistent with the TXT capabilities advertisement from DNS. Inconsistencies MUST be logged and, in STRICT mode, cause connection termination.¶
The QUIP handshake MUST be cryptographically bound to the QUIC TLS session using the TLS exporter interface [RFC8446], Section 7.5.¶
Transcript canonicalization:¶
The client and server handshake payloads are embedded as CBOR byte strings containing the exact transmitted bytes:¶
[ h'<raw client handshake bytes>', h'<raw server handshake bytes>' ]¶
Sequence of operations:¶
binding = TLS-Exporter("EXPORTER-QUIP-BINDING",
SHA-256(QUIP-CBOR(handshake_array)), 32)
¶
Governance and policy requirements for VERIFIED mode (trust anchor authorization, provider certification criteria, dispute resolution, and antitrust/competition safeguards) are deployment-specific and outside the scope of this document. Implementations in VERIFIED mode MUST rely on local policy to define acceptable trust anchors and certification authorities.¶
Trust anchors are distributed as signed CBOR objects:¶
tagged(65536, [ "trust_anchor", anchor_id, ; string (e.g., "quip-root-v1") public_key, ; 32 bytes (Ed25519) valid_from, ; Unix timestamp (seconds) valid_until, ; Unix timestamp (seconds) distribution_point, ; string URI signature ; 64 bytes (self-signed or cross-signed) ])¶
Trust anchors are distributed via:¶
tagged(65536, [ "attestation_provider", provider_NodeId, ; 32 bytes domain, ; string issuer, ; NodeId or anchor_id of issuer issued_at, ; Unix timestamp (seconds) expires_at, ; Unix timestamp (seconds, max 90 days) capabilities, ; array of strings signature ; 64 bytes (by issuer) ])¶
When receiving a provider certificate chain, peers MUST perform the following validation:¶
Path building order:¶
issuer field (NodeId or anchor_id)¶
Trust anchor matching: Trust anchors are identified by anchor_id string. Implementations MUST support exact string matching. Wildcard matching is NOT permitted.¶
Signature validation: All signatures MUST use Ed25519 [RFC8032]. Future versions may negotiate additional algorithms.¶
Expiry precedence: Certificates with expires_at in the past MUST be rejected. Trust anchors with valid_until in the past SHOULD be rejected (grace window of 24 hours permitted for rollover).¶
Rollover handling: Trust anchors SHOULD have overlapping validity windows during rollover. During overlap, either anchor is considered valid. After old anchor expires, it MUST NOT be accepted.¶
Cross-signing: Cross-signed certificates are permitted if they chain to a trust anchor. Maximum chain depth applies to the merged path.¶
Revocation check: Before accepting a certificate, check revocation status per Section 7.5. Revoked certificates MUST be rejected regardless of validity period.¶
Peers MUST enforce freshness limits on provider revocation lists:¶
| Condition | Behavior |
|---|---|
| Revocation list age < 24 hours | Normal operation |
| Revocation list age 24-72 hours | DEGRADED mode, log warning |
| Revocation list age > 72 hours | VERIFIED mode MUST fail closed; reject all VERIFIED-mode attestations |
DNS-distributed trust anchors are advisory until chained to an existing trusted anchor or implementation trust store. Implementations MUST validate the DNSSEC chain for any DNS-discovered anchor. The first anchor in a deployment MAY be installed out-of-band (e.g., via package management, configuration file, or hardcoding). Once an anchor is trusted, it may be used to validate subsequent anchor updates.¶
QUIC connection with ALPN "quip". The first client-initiated bidirectional stream opened after QUIC connection establishment (stream ID 0) is designated the QUIP Control Stream. The second client-initiated bidirectional stream (stream ID 4) is designated the QUIP Gossip Stream.¶
| Logical Role | Stream Type | Stream ID (Client) | Stream ID (Server) |
|---|---|---|---|
| Control stream | Client bidirectional | 0 | 1 |
| Gossip stream | Client bidirectional | 4 | 5 |
| Application streams | Client bidirectional | 8, 12, ... | 9, 13, ... |
All control messages (errors, rate advisories) are sent as CBOR arrays on the Control Stream.¶
Handshake sequencing: No application streams (streams other than the Control and Gossip streams) SHALL be processed until the QUIP handshake completes and transcript binding verification succeeds. The Control Stream and Gossip Stream MAY be used during handshake.¶
Phase 0: DNS Discovery¶
Query _quip._udp.domain.example SRV and TXT:¶
_quip._udp.domain.example. TXT
"v=2; profiles=basic,documents; trust=compat; quic=:443"
¶
Phase 1: QUIP Handshake (Control Stream)¶
Client sends:¶
[
2, ; version
0b111, ; profiles bitmask
"compat", ; server_trust_mode
0b01, ; identity_trust_mode (VERIFIED)
{ ; capabilities
0: true, ; datagram_support
1: ["opus", "vp9"], ; media_codecs
2: 4096 ; max_message_size
},
["revocations/#"], ; subscriptions
{ ; vector_clocks
"revocation_list": {"a.com": 42}
}
]
¶
Server responds with identical structure.¶
Both peers compute active_profiles = local.profiles & remote.profiles. If zero, send error (Section 9.3) and close.¶
+------------------+----------------------------------+ | varint length | QUIP-CBOR object | +------------------+----------------------------------+¶
The CBOR object MUST be a single complete top-level item with no trailing bytes.¶
| Logical Role | Direction | Reliability | Ordering |
|---|---|---|---|
| Control | Bidirectional | Reliable | Strict |
| Gossip | Bidirectional | Reliable | Strict |
| Application | Profile-dependent | Mixed | Mixed |
Priority order:¶
["WELL_KNOWN", "/peer"] on Control Stream (MUST)¶
The full bootstrap handshake (GOSSIP_BOOTSTRAP exchange) is defined in Section 10.¶
The signed payload is a CBOR array, not a map:¶
[ "message", payload, ; application CBOR NodeId, ; 32 bytes sequence, ; 64-bit uint (max 2^62-1) timestamp, ; 64-bit Unix milliseconds message_id ; 32 bytes (SHA-256) ]¶
The wire representation is:¶
tagged(65536, [ "message", payload, NodeId, sequence, timestamp, message_id, signature ; 64 bytes ])¶
All signatures in QUIP use standard Ed25519 [RFC8032] without pre-hashing, with explicit domain separation strings prepended to the message.¶
signature = Ed25519_sign( private_key, domain_separator || QUIP-CBOR(signed_payload_array) )¶
| Object Type | Domain Separator (UTF-8) |
|---|---|
| Message envelope |
"QUIP-MESSAGE-V1"
|
| Gossip message |
"QUIP-GOSSIP-V1"
|
| Key rotation |
"QUIP-ROTATION-V1"
|
| Attestation (subject) |
"QUIP-ATTESTATION-SUBJECT-V1"
|
| Attestation (issuer) |
"QUIP-ATTESTATION-ISSUER-V1"
|
| Violation receipt |
"QUIP-VIOLATION-V1"
|
Errors are sent as CBOR arrays on the Control Stream:¶
["ERROR", error_code, message_id, error_text]¶
Where error_code is a uint (Section 17.2), message_id is 32 bytes (may be null for handshake errors), and error_text is a human-readable string.¶
Rate advisories are sent as CBOR arrays on the Control Stream:¶
["RATE_ADVISORY", limit_type, current_rate, allowed_rate]¶
The limit_type field is a string matching the resource type being rate-limited (e.g., "message", "gossip", "datagram").¶
Sequence numbers are scoped to (genesis_NodeId, discriminator) where discriminator is the string from the signed payload array (e.g., "message", "document", "gossip").¶
Rules:¶
message_id = SHA-256("QUIP-MESSAGE-ID-V1" || QUIP-CBOR([
genesis_NodeId,
NodeId,
discriminator,
sequence,
timestamp
]))
¶
Timestamps are advisory only. Sequence numbers dominate ordering.¶
Implementations MUST NOT use timestamps for causality determination.¶
Map from issuer → counter.¶
Issuer canonical forms: Domain: text string (major type 3). NodeId: byte string, 32 bytes (major type 2). Mixed representations for the same issuer are PROHIBITED.¶
Maximum vector clock entries: 1024. Entries beyond this limit SHOULD be pruned (oldest issuers first).¶
The signed payload is a CBOR array:¶
[
"gossip",
resource_type, ; "attestations" | "revocations" | "violations"
resource_id, ; string or bytes
vector_clock, ; map {issuer: counter}
payload, ; signed resource object
ttl, ; uint (3-7)
sender_NodeId ; 32 bytes
]
¶
The wire representation is:¶
tagged(65536, [ "gossip", resource_type, resource_id, vector_clock, payload, ttl, sender_NodeId, signature ])¶
SYNC request:¶
["SYNC", resource_type, resource_id, their_clock]¶
SYNC response:¶
{
"clock": merged_clock,
"deltas": [payload1, payload2, ...],
"next_token": continuation_token, ; optional
"complete": true|false
}
¶
When updates are concurrent (neither vector clock dominates the other), the deterministic merge order is:¶
(issuer, counter) tuples as QUIP-CBOR¶
Every reliable message carries a sequence number per (sender, resource_type).¶
When a peer detects a violation (e.g., sequence gap, rate exceedance), it creates a signed violation receipt and gossips it.¶
Validation requirement: A violation receipt is considered valid only if corroborated by at least 3 independent witnesses as defined in Section 6.2. If fewer than 3 qualified domains exist in the federation, the threshold equals the number of domains.¶
Receipt signature:¶
signature = Ed25519_sign( private_key, "QUIP-VIOLATION-V1" || QUIP-CBOR(violation_data) )¶
Implementations MUST enforce the following limits:¶
| Resource | Limit | Behavior When Exceeded |
|---|---|---|
| Maximum CBOR object size | 64 KB | Reject with error |
| Maximum gossip message size | 64 KB | Reject with error |
| Maximum document size | 16 MB | Reject with error |
| Maximum attestation chain depth | 8 | Reject with error |
| Maximum rotation chain depth | 32 | Reject with error |
| Maximum vector clock entries | 1024 | Prune oldest |
| Maximum replay cache entries | 100,000 | LRU eviction |
| Maximum pending sequence gaps | 256 | Discard oldest |
| Profile | Required Features |
|---|---|
| Basic | NodeId, attestations, DANE (COMPAT), message envelope, rate limiting, gossip |
| Documents (Companion Document) | Adds: content addressing, schema registry, collections. Specified in a separate document. |
| Media (Experimental) | See Section 14 |
The Documents profile features (content addressing by hash, schema registry, document collections) are specified in a companion Internet-Draft titled "QUIP Documents Profile".¶
The following features are marked experimental in this version and MAY change incompatibly in future versions. Implementations SHOULD log a warning when experimental features are used.¶
| Feature | Status |
|---|---|
| Media profile | Incomplete; separate document planned |
| Routing resource type | Not fully specified; use at own risk |
The Media profile uses QUIC datagrams as specified in [RFC9221].¶
QUIP defends against: domain impersonation (via subject signatures), replay attacks (via message_id cache), BGP hijacking (via DANE binding), DNS poisoning (via DNSSEC), split-brain/fork (via deterministic merge), gossip amplification (via TTL and rate limits), Sybil witnesses (via independent witness definition — raises operational cost of Sybil-style witness fabrication).¶
QUIP does NOT defend against: anonymity attacks, metadata confidentiality, global passive adversaries, Byzantine consensus, economic Sybil resistance, or witness collusion (relies on legal/commercial incentives).¶
Domain separation (Section 9.2) prevents cross-context replay. The message_id cache provides per-message protection.¶
DNS downgrade protection (Section 6.3) and handshake transcript binding (Section 6.4) prevent silent capability stripping. STRICT mode refuses downgrades.¶
QUIP-CBOR (Section 18) eliminates encoding ambiguity. Duplicate keys and indefinite lengths are rejected. QUIP-CBOR is defined as an application profile of [RFC8949].¶
Linkability through rotation chains: Key rotation preserves identity continuity for accountability. All keys in a rotation chain are cryptographically linked to the genesis NodeId. Rotating keys does NOT provide unlinkability or anonymity.¶
IANA is requested to register the following ALPN protocol ID:¶
IANA is requested to create a registry titled "QUIP Error Codes" with the following initial contents:¶
| Code | Name | Description |
|---|---|---|
| 1 | INVALID_SIGNATURE | Signature verification failed |
| 2 | ATTESTATION_EXPIRED | Attestation validity period exceeded |
| 3 | DNSSEC_FAILURE | DNSSEC validation failed |
| 4 | RATE_LIMIT_EXCEEDED | Quota exceeded |
| 5 | DUPLICATE_MESSAGE | message_id already seen |
| 6 | KEY_ROTATED | Sender's NodeId rotated |
| 7 | UNSUPPORTED_VERSION | Schema version not supported |
| 8 | GOSSIP_RATE_LIMIT | Gossip update rate exceeded |
| 9 | PROFILE_MISMATCH | No common profile |
| 10 | HASH_MISMATCH | Document hash mismatch |
| 11 | DATAGRAM_NOT_SUPPORTED | Peer does not support datagrams |
| 12 | GOSSIP_BOOTSTRAP_FAILED | Bootstrap failed |
| 13 | KEY_COMPROMISED | Key compromise reported |
| 14 | GOSSIP_SYNC_TIMEOUT | Anti-entropy timeout |
Registration policy: IETF Review for codes 0-127. Codes 128-255 are reserved for application-specific extensions. Error code 0 is reserved and MUST NOT be used.¶
IANA is requested to register the following CBOR tag in the CBOR Tags registry [RFC9277]:¶
QUIP defines a strict deterministic CBOR profile called the QUIP Deterministic CBOR Profile (QDP). This is an application profile, not a replacement for [RFC8949] canonical CBOR. QDP is used exclusively within QUIP protocol messages.¶
| Class | Type | Ordering Rule |
|---|---|---|
| 1 | Unsigned integers | Numeric ascending, shortest encoding first |
| 2 | Negative integers | Numeric ascending (more negative first) |
| 3 | Byte strings | Length-ordered, then lexicographic |
| 4 | Text strings | Length-ordered, then UTF-8 bytewise lexicographic |
Prohibited constructs: duplicate map keys, indefinite-length items, floating point values, non-minimal UTF-8, CBOR simple values other than false/true/null.¶
Implementations MUST persist vector clocks for all tracked resources, sequence number state per (genesis_NodeId, discriminator), revocation state for known peers, and peer relationship state. Replay cache persistence is OPTIONAL.¶
If sequence state is lost after restart, the implementation MUST log a critical error, rotate the NodeId (Section 5.3) to start a new sequence space, and NOT reuse prior sequence numbers.¶