QUICWG F. Rochet Internet-Draft UNamur Intended status: Standards Track 4 May 2026 Expires: 5 November 2026 Reverso for the QUIC protocol draft-frochet-quicwg-reverso-for-quic-01 Abstract This document describes a QUIC version re-designing the layout of the QUIC protocol to avoid memory fragmentation at the receiver and allows implementers seeking a more efficient implementation to have the option to implement contiguous zero-copy at the receiver. This document describes the change from QUIC v1 required in packet formats, variable-length integers and frame formats. Everything else from QUIC v1 described in [RFC9000] is untouched. About This Document This note is to be removed before publishing as an RFC. Status information for this document may be found at https://datatracker.ietf.org/doc/draft-frochet-quicwg-reverso-for- quic/. Source for this draft and an issue tracker can be found at https://github.com/https://github.com/frochet/draft-rochet-reverso- for-quic. Status of This Memo 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 5 November 2026. Copyright Notice 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. Table of Contents 1. Introduction 2. Goals 3. Conventions and Definitions 4. Streams 5. Frame Formats 6. Packet Formats 6.1. Header Protection 6.2. Stream ID encoding (to debate) 6.3. Frame ordering 7. Variable-Length Integer Encoding 8. Security, Safety and Liveness Considerations 8.1. Avoiding Data Corruption 8.2. Manipulating Short Header bits may cause hitting Stream Limits 9. References 9.1. Normative References 9.2. Informative References Appendix A. Acknowledgments {:numbered="false"} Author's Address 1. Introduction QUIC is a general-purpose transport protocol with mandatory encryption leveraged from a TLS 1.3 key exchange. QUIC is specified in [RFC9000], and is the result of several years of efforts from several major companies, independent individuals and academics. One of the main benefits of QUIC is to resist ossification thanks to a two-level encryption design (header and payload), supporting extensions and modifications of internal QUIC information to resist friction from independent lower layers at deployment time. However, it is of notoriety that the QUIC design is CPU costly. The root cause of QUIC's high CPU cost isn't unique, and this document addresses one of them: a misalignment between QUIC's protocol specification and encryption integration. Indeed, the QUIC design in [RFC9000] unavoidably fragments Application Data and forces any implementation to perform at least a memory copy to provide a contiguous bytestream abstraction to the upper layer, at the receiver. This document suggests another QUIC Version demanding the Stream frame to always be the first frame if any, and reversing the wire representation of the QUIC protocol. These two changes offer the opportunity for implementers to provide a contiguous zero-copy abstraction at the receiver side for each stream using the decryption internal copy for data reassembly. With this version, QUIC frames are encoded in reverse ordering and would be written and processed from right to left, instead of the usual left to right as in any protocol. The stream frame may be followed by any number of control frames up to the packet boundary. Other stream frames may be packed within the same packet, although receiver implementations would not be able to process them in contiguous zero-copy. 2. Goals We aim to change how the QUIC protocol specifies its frames to support a stream abstraction with the option to offer a contiguous zero-copy interface to the upper layer. A few more bytes also have to be added within the protected short header. Those changes are, however, engineered with goals to: * Minimizing added control overheads. * Not requiring a different frame encoding/decoding code logic. Despite the change of the wire format, the code for writing and processing QUIC frames does not need adaptation as long as a protocol-independent buffer abstraction to write and read from right to left exists. * Not mandating existing QUIC implementations to support this version. Can fallback to QUIC v1 (by the QUIC protocol negotiation design). * Not modifying any of the QUIC's transport properties (i.e., HoL blocking avoidance, multiplexing, extensibility, ...) and not conflicting with the goals of any ongoing work on QUIC extensions (e.g., MPQUIC) otherwise than by requiring them to change their wire representation as well. * Not impacting QUIC's security/safety assuming implementers follow added guidance to Reverso. * Keeping Encryption/decryption compatible with the current usage of existing crypto libraries. 3. Conventions and Definitions 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. 4. Streams Stream ID values start at 1. We reserve the value 0 to indicate within the new short header (see Section 6.1) that no stream frame is packed within the encrypted payload. 5. Frame Formats Frames' structure written on the wire is altered in this QUIC version to support a backward processing of QUIC packets. All the other frames are straightforward to adapt from [RFC9000]. Essentially, on [RFC9000], each frame begins with a Frame Type followed by additional type-dependent fields, and is represented as this: Frame { Frame Type (i), Type-Dependent Fields (..), } This representation follows the implicit rule that what we specify, from top to bottom, is written and read from left to right on the wire. If QUIC Reverso is used, frames are reversed. Type-dependent fields appear first (from left to right on the wire), and the frame terminates with the Frame Type. We represent those frames by reversing their representation in specifications: Frame { Type-Dependent Fields (..), Frame Type (i), } The choice of order of Type-Dependent Fields only matters to ease the transition and adaptation of existing code handling [RFC9000]'s frame format. Reversing the existing ordering and not making other changes within the relative order of elements may support straightforward adaptation of existing code. For example, in [RFC9000], the MAX_STREAM_DATA Frame is defined as: MAX_STREAM_DATA Frame { Type (i) = 0x11, Stream ID (i), Maximum Stream Data (i), } Which would translate to: MAX_STREAM_DATA Frame { Maximum Stream Data (i), Stream ID (i), Type (i) = 0x11, } 6. Packet Formats For implementers to take advantage of Reverso and use the decryption internal copy for data reassembly, we require to know the Stream ID of any stream frame within the payload and the data offset. These two integers are added to the QUIC short header and protected with the mask using a XOR. In QUIC v1, 5 out of 16 bytes available are being used. In Reverso, we would use 13 out of 16 bytes. 6.1. Header Protection The header of 1-RTT short header packets is extended to add at most 8 bytes of information, requiring a 13-byte mask. Application of the mask follows the same procedure as specified in [RFC9001], as a minimum of 16 bytes are currently available from the current header protection algorithms. 1-RTT Packet { Header Form (1) = 0, Fixed Bit (1) = 1, Spin Bit (1), Reserved Bits (2), # Protected Key Phase (1), # Protected Packet Number Length (2), # Protected Destination Connection ID (0..160), Packet Number (8..32), # Protected Stream ID (8..32) # Protected Offset (8..32) # Protected Protected Payload (0..72), # Skipped Part Protected Payload (128), # Sampled Part Protected Payload (..), # Remainder } The 1-RTT packets has the following modifications from QUIC v1: * Packet Number: The Packet Number field is 1 to 4 bytes long, with the least two significant bits of the last byte containing the length of the Stream ID. This length is encoded as an unsigned two-bit integer that is one less than the length of the Stream ID field in bytes. This field is protected using [RFC9001]'s mask, which can consume a maximum of 5 bytes (including the first header byte) from the guaranteed 16 bytes. * Stream ID: The Stream ID field is 1 to 4 bytes long, with the least two significant bits of the last byte containing the length of the Offset. This length is encoded as an unsigned two-bit integer that is one less than the length of the Offset field in bytes. A 1-byte value of 0 for this field is reserved to indicate that the encrypted payload does not contain any Stream frame. This field is protected using [RFC9001]'s mask, up to consume 9 bytes from the guaranteed 16 bytes in total. * Offset: The Offset field is 1 to 4 bytes long, and encodes a value based on the knowledge of the maximum acknowledged offset, similar to the Packet Number field but encoding a value based on the highest acknowledged offset. On the receiver, the decoding procedure is similar to decoding packet numbers. This field is protected using [RFC9001]'s mask, up to consume 13 bytes from the guaranteed 16 bytes in total. * Protected Payload Skipped Part's length: 72 bits are skipped instead of 24. 24 bits are skipped in QUIC v1 in order to account for the maximum (yet unknown) length of the Packet Number when sampling the encrypted payload for header decryption. Since we add variable integers, we need sampling further away to guarantee always falling into the AEAD encryption (and/or tag). We need skipping 72 bits to account for the maximum combined (yet unknown) lengths of Packet Number, Stream ID and offset. This affects the minimum payload length for preparing a QUIC packet at the sender, which was following the relation in QUIC v1: pn_len + min_payload_len + tag_len = 4 + sample_len => min_payload_len := 4 + sample_len - tag_len - pn_len => min_payload_len := 20 - tag_len - pn_len as defined in [RFC9001], where a safe static value can be set to 3 bytes for min_payload_len (i.e., it is the max value of the upper relation). In VReverso, the relation becomes: pn_len + stream_id_len + offset_len + min_payload_len + tag_len = 12 + sample_len => min_payload_len := 12 + sample_len - tag_len - pn_len - stream_id_len - offset_len => min_payload_len := 28 - tag_len - pn_len - stream_id_len - offset_len A safe static value for min_payload_len can be set to 9 bytes in implementations. 6.2. Stream ID encoding (to debate) The QUIC v1 protocol supports up to 2^{60} maximum streams. A QUIC Reverso implementation must encode a Stream ID within at most 30 bits in its header. Due to the monotonic increasing nature of Stream IDs, we can work out a solution that still permits up to 2^{60} maximum streams, but constraints endpoints to fire at most 2^{30} new streams at any time. We consider (up to debate) this constraint to exceed any reasonable usage of the QUIC protocol given the memory requirement to hold up to 2^{30} opened streams. Different solutions are possible. An approach could be to reuse packet number encoding/ decoding, but based on acknowledged new streams. 6.3. Frame ordering In Reverso, a Stream Frame, if any, MUST be the first frame within the payload. The Stream frame can be followed by any number of control frames up to the packet boundary. Any other Stream frame SHOULD NOT be added within the same QUIC packet, unless in scenarios where multiplexing may bring more benefits than contiguous zero-copy (e.g., multiplexed HTTP queries within a single packet). 7. Variable-Length Integer Encoding QUIC v1 uses variable-length encoding for non-negative integer values to encode fewer bytes on the wire than usual host representations. In QUIC v1 the encoding reserves the two most significant bits of the first byte, and encodes the integer in the remaining bits in the network byte order. In this version, we encode the length in the two least significant bits of the last byte to accommodate processing the information by rewinding the buffer. The remaining bits encode the integer value in the network byte order. +======+========+=============+=======================+ | 2LSB | Length | Usable Bits | Range | +======+========+=============+=======================+ | 00 | 1 | 6 | 0-63 | +------+--------+-------------+-----------------------+ | 01 | 2 | 14 | 0-16383 | +------+--------+-------------+-----------------------+ | 10 | 4 | 30 | 0-1073741823 | +------+--------+-------------+-----------------------+ | 11 | 8 | 62 | 0-4611686018427387903 | +------+--------+-------------+-----------------------+ Table 1: Summary of Integer Encodings with Reverso 8. Security, Safety and Liveness Considerations The goal of this section is to discuss careful considerations which a QUIC Reverso implementation must consider while implementing a contiguous zero-copy receiver interface. 8.1. Avoiding Data Corruption Contiguous zero-copy with Reverso is obtained by exploiting the added information in the short header and the decryption's internal copy to reassemble data fragments. For payload decryption, the Stream ID contained within the short header should be used as a buffer selection mechanism, and the offset is used to locate where to decrypt the packet content within the buffer. AEAD implementations may write at the destination address specified by the caller even if the decryption fails. Therefore, receivers must track the highest contiguous received authenticated offset for each stream and always decrypt in place any packet containing an offset below or equal to the tracked value. Furthermore, implementers must be careful with data gaps within a stream buffer created due to out-of-order packets, where the decryption of a late out-of-order packet may override part of the existing buffered data. Different implementation solutions are possible to deal with this issue. In all cases it involves a copy of the decrypted data. A possible solution is to apply the following logic: if the packet's data is to be decrypted at a location higher than the highest received contiguous offset + 1, and if the AEAD ciphertext is of size N and aimed at location L in the stream buffer, check whether the range L..L+N does not contain any previously decrypted data. Decrypt in place if the answer is yes to avoid data corruption, and safely copy to location L in the stream buffer. 8.2. Manipulating Short Header bits may cause hitting Stream Limits A QUIC Reverso implementation may allocate a new stream context before a packet containing a new Stream is decrypted. If an on-path adversary flips bits in the encrypted header it would result in a flipped bit in the decrypted header as per [RFC9001]'s XOR properties used for header protection. Such an event would be detected in the AEAD decryption phase, since the AEAD decryption would fail. In the meantime, any memory allocated related to a new Stream context resulting from the adversarial manipulation would need to be released, and any stream limit modification would need to be credited back. 9. References 9.1. Normative References [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, . [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, . 9.2. Informative References [RFC9000] Iyengar, J., Ed. and M. Thomson, Ed., "QUIC: A UDP-Based Multiplexed and Secure Transport", RFC 9000, DOI 10.17487/RFC9000, May 2021, . [RFC9001] Thomson, M., Ed. and S. Turner, Ed., "Using TLS to Secure QUIC", RFC 9001, DOI 10.17487/RFC9001, May 2021, . Appendix A. Acknowledgments {:numbered="false"} TODO acknowledge. Author's Address Florentin Rochet UNamur Email: florentin.rochet@unamur.be