]> git.ipfire.org Git - thirdparty/openssl.git/blob - ssl/quic/quic_rstream.c
Support SSL_OP_CLEANSE_PLAINTEXT on QUIC streams
[thirdparty/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 }