xref: /freebsd/crypto/openssl/doc/designs/quic-design/stream-receive-buffers.md (revision e7be843b4a162e68651d3911f0357ed464915629)
1*e7be843bSPierre ProncheryStream Receive Buffers
2*e7be843bSPierre Pronchery======================
3*e7be843bSPierre Pronchery
4*e7be843bSPierre ProncheryThis is a QUIC specific module that retains the received stream data
5*e7be843bSPierre Proncheryuntil the application reads it with SSL_read() or any future stream read
6*e7be843bSPierre Proncherycalls.
7*e7be843bSPierre Pronchery
8*e7be843bSPierre ProncheryReceive Buffers requirements for MVP
9*e7be843bSPierre Pronchery------------------------------------
10*e7be843bSPierre Pronchery
11*e7be843bSPierre ProncheryThese are the requirements that were identified for MVP:
12*e7be843bSPierre Pronchery
13*e7be843bSPierre Pronchery- As packets with stream frames are received in arbitrary frames the
14*e7be843bSPierre Pronchery  received data must be stored until all the data with earlier offsets
15*e7be843bSPierre Pronchery  are received.
16*e7be843bSPierre Pronchery- As packets can be received before application calls SSL_read() to read
17*e7be843bSPierre Pronchery  the data the data must be stored.
18*e7be843bSPierre Pronchery- The application should be able to set the limit on how much data should
19*e7be843bSPierre Pronchery  be stored. The flow controller should be used to limit the peer to not send
20*e7be843bSPierre Pronchery  more data. Without the flow control limit a rogue peer could trigger
21*e7be843bSPierre Pronchery  a DoS via unlimited flow of incoming stream data frames.
22*e7be843bSPierre Pronchery- After the data is passed via SSL_read() to the application the stored
23*e7be843bSPierre Pronchery  data can be released and flow control limit can be raised.
24*e7be843bSPierre Pronchery- As the peer can recreate stream data frames when resending them, the
25*e7be843bSPierre Pronchery  implementation must be able to handle properly frames with partially
26*e7be843bSPierre Pronchery  or fully overlapping data with previously received frames.
27*e7be843bSPierre Pronchery
28*e7be843bSPierre ProncheryOptional Receive Buffers requirements
29*e7be843bSPierre Pronchery-------------------------------------
30*e7be843bSPierre Pronchery
31*e7be843bSPierre ProncheryThese are optional features of the stream receive buffers implementation.
32*e7be843bSPierre ProncheryThey are not required for MVP but they are otherwise desirable:
33*e7be843bSPierre Pronchery
34*e7be843bSPierre Pronchery- To support a single copy operation with a future stream read call
35*e7be843bSPierre Pronchery  the received data should not be copied out of the decrypted packets to
36*e7be843bSPierre Pronchery  store the data. The only information actually stored would be a list
37*e7be843bSPierre Pronchery  of offset, length, and pointers to data, along with a pointer to the
38*e7be843bSPierre Pronchery  decrypted QUIC packet that stores the actual frame.
39*e7be843bSPierre Pronchery
40*e7be843bSPierre ProncheryProposed new public API calls
41*e7be843bSPierre Pronchery-----------------------------
42*e7be843bSPierre Pronchery
43*e7be843bSPierre Pronchery```C
44*e7be843bSPierre Proncheryint SSL_set_max_stored_stream_data(SSL *stream, size_t length);
45*e7be843bSPierre Pronchery```
46*e7be843bSPierre Pronchery
47*e7be843bSPierre ProncheryThis function adjusts the current data flow control limit on the `stream`
48*e7be843bSPierre Proncheryto allow storing `length` bytes of quic stream data before it is read by
49*e7be843bSPierre Proncherythe application.
50*e7be843bSPierre Pronchery
51*e7be843bSPierre ProncheryOpenSSL handles sending MAX_STREAM_DATA frames appropriately when the
52*e7be843bSPierre Proncheryapplication reads the stored data.
53*e7be843bSPierre Pronchery
54*e7be843bSPierre Pronchery```C
55*e7be843bSPierre Proncheryint SSL_set_max_unprocessed_packet_data(SSL *connection,
56*e7be843bSPierre Pronchery                                        size_t length);
57*e7be843bSPierre Pronchery```
58*e7be843bSPierre Pronchery
59*e7be843bSPierre ProncheryThis sets the limit on unprocessed quic packet data `length` in bytes that
60*e7be843bSPierre Proncheryis allowed to be allocated for the `connection`.
61*e7be843bSPierre ProncherySee the [Other considerations](#other-considerations) section below.
62*e7be843bSPierre Pronchery
63*e7be843bSPierre ProncheryInterfaces to other QUIC implementation modules
64*e7be843bSPierre Pronchery-----------------------------------------------
65*e7be843bSPierre Pronchery
66*e7be843bSPierre Pronchery### Front End I/O API
67*e7be843bSPierre Pronchery
68*e7be843bSPierre ProncherySSL_read() copies data out of the stored buffers if available and
69*e7be843bSPierre Proncheryeventually triggers release of stored unprocessed packet(s).
70*e7be843bSPierre Pronchery
71*e7be843bSPierre ProncherySSL_peek(), SSL_pending(), SSL_has_pending() peek into the stored
72*e7be843bSPierre Proncherybuffers for any information about the stored data.
73*e7be843bSPierre Pronchery
74*e7be843bSPierre Pronchery### RX Depacketizer
75*e7be843bSPierre Pronchery
76*e7be843bSPierre ProncheryThe Receive Buffers module obtains the stream data via the ssl_queue_data()
77*e7be843bSPierre Proncherycallback.
78*e7be843bSPierre Pronchery
79*e7be843bSPierre ProncheryThe module uses ossl_qrx_pkt_wrap_up_ref() and ossl_qrx_pkt_wrap_release()
80*e7be843bSPierre Proncheryfunctions to keep and release decrypted packets with unprocessed data.
81*e7be843bSPierre Pronchery
82*e7be843bSPierre Pronchery### Flow Control
83*e7be843bSPierre Pronchery
84*e7be843bSPierre ProncheryThe Receive Buffers module provides an appropriate value for the Flow
85*e7be843bSPierre ProncheryControl module to send MAX_DATA and MAX_STREAM_DATA frames. Details
86*e7be843bSPierre ProncheryTBD.
87*e7be843bSPierre Pronchery
88*e7be843bSPierre Pronchery### QUIC Read Record Layer
89*e7be843bSPierre Pronchery
90*e7be843bSPierre ProncheryThe Receive Buffers module needs to know whether it should stop holding
91*e7be843bSPierre Proncherythe decrypted quic packets and start copying the stream data due to
92*e7be843bSPierre Proncherythe limit reached. See the `SSL_set_max_unprocessed_quic_packet_data()`
93*e7be843bSPierre Proncheryfunction above and the [Other considerations](#other-considerations) section
94*e7be843bSPierre Proncherybelow. Details TBD.
95*e7be843bSPierre Pronchery
96*e7be843bSPierre ProncheryImplementation details
97*e7be843bSPierre Pronchery----------------------
98*e7be843bSPierre Pronchery
99*e7be843bSPierre ProncheryThe QUIC_RSTREAM object holds the received stream data in the SFRAME_LIST
100*e7be843bSPierre Proncherystructure. This is a sorted list of partially (never fully) overlapping
101*e7be843bSPierre Proncherydata frames. Each list item holds a pointer to the received packet
102*e7be843bSPierre Proncherywrapper for refcounting and proper release of the received packet
103*e7be843bSPierre Proncherydata once the stream data is read by the application.
104*e7be843bSPierre Pronchery
105*e7be843bSPierre ProncheryEach SFRAME_LIST item has range.start and range.end values greater
106*e7be843bSPierre Proncherythan the range.start and range.end values of the previous item in the list.
107*e7be843bSPierre ProncheryThis invariant is ensured on the insertion of overlapping stream frames.
108*e7be843bSPierre ProncheryAny redundant frames are released. Insertion at the end of the list
109*e7be843bSPierre Proncheryis optimised as in the ideal situation when no packets are lost we
110*e7be843bSPierre Proncheryalways just append new frames.
111*e7be843bSPierre Pronchery
112*e7be843bSPierre ProncherySee `include/internal/quic_stream.h` and `include/internal/quic_sf_list.h`
113*e7be843bSPierre Proncheryfor internal API details.
114*e7be843bSPierre Pronchery
115*e7be843bSPierre ProncheryOther considerations
116*e7be843bSPierre Pronchery--------------------
117*e7be843bSPierre Pronchery
118*e7be843bSPierre ProncheryThe peer is allowed to recreate the stream data frames. As we aim for
119*e7be843bSPierre Proncherya single-copy operation a rogue peer could use this to override the stored
120*e7be843bSPierre Proncherydata limits by sending duplicate frames with only slight changes in the
121*e7be843bSPierre Proncheryoffset. For example: 1st frame - offset 0 length 1000, 2nd frame -
122*e7be843bSPierre Proncheryoffset 1 length 1000, 3rd frame - offset 2 length 1000, and so on. We
123*e7be843bSPierre Proncherywould have to keep the packet data for all these frames which would
124*e7be843bSPierre Proncheryeffectively raise the stream data flow control limit quadratically.
125*e7be843bSPierre Pronchery
126*e7be843bSPierre ProncheryAnd this is not the only way how a rogue peer could make us occupy much
127*e7be843bSPierre Proncherymore data than what is allowed by the stream data flow control limit
128*e7be843bSPierre Proncheryin the single-copy scenario.
129*e7be843bSPierre Pronchery
130*e7be843bSPierre ProncheryAlthough intuitively the MAX_DATA flow control limit might be used to
131*e7be843bSPierre Proncherysomehow limit the allocated packet buffer size, it is defined as sum
132*e7be843bSPierre Proncheryof allowed data to be sent across all the streams in the connection instead.
133*e7be843bSPierre ProncheryThe packet buffer will contain much more data than just the stream frames
134*e7be843bSPierre Proncheryespecially with a rogue peer, that means MAX_DATA limit cannot be used
135*e7be843bSPierre Proncheryto limit the memory occupied by packet buffers.
136*e7be843bSPierre Pronchery
137*e7be843bSPierre ProncheryTo resolve this problem, we fall back to copying the data off the
138*e7be843bSPierre Proncherydecrypted packet buffer once we reach a limit on unprocessed decrypted
139*e7be843bSPierre Proncherypackets. We might also consider falling back to copying the data in case
140*e7be843bSPierre Proncherywe receive stream data frames that are partially overlapping and one frame
141*e7be843bSPierre Proncherynot being a subrange of the other.
142*e7be843bSPierre Pronchery
143*e7be843bSPierre ProncheryBecause in MVP only a single bidirectional stream to receive
144*e7be843bSPierre Proncheryany data will be supported, the MAX_DATA flow control limit should be equal
145*e7be843bSPierre Proncheryto MAX_STREAM_DATA limit for that stream.
146