Support SSL_OP_CLEANSE_PLAINTEXT on QUIC streams
[openssl.git] / ssl / quic / quic_rstream.c
1 /*
2 * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License").  You may not use
5 * this file except in compliance with the License.  You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9 #include <openssl/err.h>
10 #include "internal/common.h"
11 #include "internal/time.h"
12 #include "internal/quic_stream.h"
13 #include "internal/quic_sf_list.h"
14 #include "internal/ring_buf.h"
15
16 struct quic_rstream_st {
17     SFRAME_LIST fl;
18     QUIC_RXFC *rxfc;
19     OSSL_STATM *statm;
20     UINT_RANGE head_range;
21     struct ring_buf rbuf;
22 };
23
24 QUIC_RSTREAM *ossl_quic_rstream_new(QUIC_RXFC *rxfc,
25                                     OSSL_STATM *statm, size_t rbuf_size)
26 {
27     QUIC_RSTREAM *ret = OPENSSL_zalloc(sizeof(*ret));
28
29     if (ret == NULL)
30         return NULL;
31
32     ring_buf_init(&ret->rbuf);
33     if (!ring_buf_resize(&ret->rbuf, rbuf_size)) {
34         OPENSSL_free(ret);
35         return NULL;
36     }
37
38     ossl_sframe_list_init(&ret->fl);
39     ret->rxfc = rxfc;
40     ret->statm = statm;
41     return ret;
42 }
43
44 void ossl_quic_rstream_free(QUIC_RSTREAM *qrs)
45 {
46     if (qrs == NULL)
47         return;
48
49     ossl_sframe_list_destroy(&qrs->fl);
50     ring_buf_destroy(&qrs->rbuf);
51     OPENSSL_free(qrs);
52 }
53
54 int ossl_quic_rstream_queue_data(QUIC_RSTREAM *qrs, OSSL_QRX_PKT *pkt,
55                                  uint64_t offset,
56                                  const unsigned char *data, uint64_t data_len,
57                                  int fin)
58 {
59     UINT_RANGE range;
60
61     if ((data == NULL && data_len != 0) || (data_len == 0 && fin == 0)) {
62         /* empty frame allowed only at the end of the stream */
63         ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
64         return 0;
65     }
66
67     range.start = offset;
68     range.end = offset + data_len;
69
70     return ossl_sframe_list_insert(&qrs->fl, &range, pkt, data, fin);
71 }
72
73 static int read_internal(QUIC_RSTREAM *qrs, unsigned char *buf, size_t size,
74                          size_t *readbytes, int *fin, int drop)
75 {
76     void *iter = NULL;
77     UINT_RANGE range;
78     const unsigned char *data;
79     uint64_t offset = 0;
80     size_t readbytes_ = 0;
81     int fin_ = 0, ret = 1;
82
83     while (ossl_sframe_list_peek(&qrs->fl, &iter, &range, &data, &fin_)) {
84         size_t l = (size_t)(range.end - range.start);
85
86         if (l > size) {
87             l = size;
88             fin_ = 0;
89         }
90         offset = range.start + l;
91         if (l == 0)
92             break;
93
94         if (data == NULL) {
95             size_t max_len;
96
97             data = ring_buf_get_ptr(&qrs->rbuf, range.start, &max_len);
98             if (!ossl_assert(data != NULL))
99                 return 0;
100             if (max_len < l) {
101                 memcpy(buf, data, max_len);
102                 size -= max_len;
103                 buf += max_len;
104                 readbytes_ += max_len;
105                 l -= max_len;
106                 data = ring_buf_get_ptr(&qrs->rbuf, range.start + max_len,
107                                         &max_len);
108                 if (!ossl_assert(data != NULL) || !ossl_assert(max_len > l))
109                     return 0;
110             }
111         }
112
113         memcpy(buf, data, l);
114         size -= l;
115         buf += l;
116         readbytes_ += l;
117         if (size == 0)
118             break;
119     }
120
121     if (drop && offset != 0) {
122         ret = ossl_sframe_list_drop_frames(&qrs->fl, offset);
123         ring_buf_cpop_range(&qrs->rbuf, 0, offset - 1, qrs->fl.cleanse);
124     }
125
126     if (ret) {
127         *readbytes = readbytes_;
128         *fin = fin_;
129     }
130
131     return ret;
132 }
133
134 static OSSL_TIME get_rtt(QUIC_RSTREAM *qrs)
135 {
136     OSSL_TIME rtt;
137
138     if (qrs->statm != NULL) {
139         OSSL_RTT_INFO rtt_info;
140
141         ossl_statm_get_rtt_info(qrs->statm, &rtt_info);
142         rtt = rtt_info.smoothed_rtt;
143     } else {
144         rtt = ossl_time_zero();
145     }
146     return rtt;
147 }
148
149 int ossl_quic_rstream_read(QUIC_RSTREAM *qrs, unsigned char *buf, size_t size,
150                            size_t *readbytes, int *fin)
151 {
152     OSSL_TIME rtt = get_rtt(qrs);
153
154     if (!read_internal(qrs, buf, size, readbytes, fin, 1))
155         return 0;
156
157     if (qrs->rxfc != NULL
158         && !ossl_quic_rxfc_on_retire(qrs->rxfc, *readbytes, rtt))
159         return 0;
160
161     return 1;
162 }
163
164 int ossl_quic_rstream_peek(QUIC_RSTREAM *qrs, unsigned char *buf, size_t size,
165                            size_t *readbytes, int *fin)
166 {
167     return read_internal(qrs, buf, size, readbytes, fin, 0);
168 }
169
170 int ossl_quic_rstream_available(QUIC_RSTREAM *qrs, size_t *avail, int *fin)
171 {
172     void *iter = NULL;
173     UINT_RANGE range;
174     const unsigned char *data;
175     uint64_t avail_ = 0;
176
177     while (ossl_sframe_list_peek(&qrs->fl, &iter, &range, &data, fin))
178         avail_ += range.end - range.start;
179
180 #if SIZE_MAX < UINT64_MAX
181     *avail = avail_ > SIZE_MAX ? SIZE_MAX : (size_t)avail_;
182 #else
183     *avail = (size_t)avail_;
184 #endif
185     return 1;
186 }
187
188 int ossl_quic_rstream_get_record(QUIC_RSTREAM *qrs,
189                                  const unsigned char **record, size_t *rec_len,
190                                  int *fin)
191 {
192     const unsigned char *record_ = NULL;
193     size_t rec_len_, max_len;
194
195     if (!ossl_sframe_list_lock_head(&qrs->fl, &qrs->head_range, &record_, fin)) {
196         /* No head frame to lock and return */
197         *record = NULL;
198         *rec_len = 0;
199         return 1;
200     }
201
202     /* if final empty frame, we drop it immediately */
203     if (qrs->head_range.end == qrs->head_range.start) {
204         if (!ossl_assert(*fin))
205             return 0;
206         if (!ossl_sframe_list_drop_frames(&qrs->fl, qrs->head_range.end))
207             return 0;
208     }
209
210     rec_len_ = (size_t)(qrs->head_range.end - qrs->head_range.start);
211
212     if (record_ == NULL && rec_len_ != 0) {
213         record_ = ring_buf_get_ptr(&qrs->rbuf, qrs->head_range.start,
214                                    &max_len);
215         if (!ossl_assert(record_ != NULL))
216             return 0;
217         if (max_len < rec_len_) {
218             rec_len_ = max_len;
219             qrs->head_range.end = qrs->head_range.start + max_len;
220         }
221     }
222
223     *rec_len = rec_len_;
224     *record = record_;
225     return 1;
226 }
227
228
229 int ossl_quic_rstream_release_record(QUIC_RSTREAM *qrs, size_t read_len)
230 {
231     uint64_t offset;
232
233     if (!ossl_sframe_list_is_head_locked(&qrs->fl))
234         return 0;
235
236     if (read_len > qrs->head_range.end - qrs->head_range.start) {
237         if (read_len != SIZE_MAX)
238             return 0;
239         offset = qrs->head_range.end;
240     } else {
241         offset = qrs->head_range.start + read_len;
242     }
243
244     if (!ossl_sframe_list_drop_frames(&qrs->fl, offset))
245         return 0;
246
247     if (offset > 0)
248         ring_buf_cpop_range(&qrs->rbuf, 0, offset - 1, qrs->fl.cleanse);
249
250     if (qrs->rxfc != NULL) {
251         OSSL_TIME rtt = get_rtt(qrs);
252
253         if (!ossl_quic_rxfc_on_retire(qrs->rxfc, offset, rtt))
254             return 0;
255     }
256
257     return 1;
258 }
259
260 static int write_at_ring_buf_cb(uint64_t logical_offset,
261                                 const unsigned char *buf,
262                                 size_t buf_len,
263                                 void *cb_arg)
264 {
265     struct ring_buf *rbuf = cb_arg;
266
267     return ring_buf_write_at(rbuf, logical_offset, buf, buf_len);
268 }
269
270 int ossl_quic_rstream_move_to_rbuf(QUIC_RSTREAM *qrs)
271 {
272     if (ring_buf_avail(&qrs->rbuf) == 0)
273         return 0;
274     return ossl_sframe_list_move_data(&qrs->fl,
275                                       write_at_ring_buf_cb, &qrs->rbuf);
276 }
277
278 int ossl_quic_rstream_resize_rbuf(QUIC_RSTREAM *qrs, size_t rbuf_size)
279 {
280     /* TODO(QUIC): Do we need to distinguish different error conditions ? */
281     if (ossl_sframe_list_is_head_locked(&qrs->fl))
282         return 0;
283
284     if (!ring_buf_resize(&qrs->rbuf, rbuf_size))
285         return 0;
286
287     return 1;
288 }
289
290 void ossl_quic_rstream_set_cleanse(QUIC_RSTREAM *qrs, int cleanse)
291 {
292     qrs->fl.cleanse = cleanse;
293 }