]> git.ipfire.org Git - thirdparty/openssl.git/blob - ssl/quic/quic_port.c
QUIC PORT, CHANNEL: Move DEMUX and default packet handling out of CHANNEL
[thirdparty/openssl.git] / ssl / quic / quic_port.c
1 /*
2 * Copyright 2023 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
10 #include "internal/quic_port.h"
11 #include "internal/quic_channel.h"
12 #include "quic_port_local.h"
13 #include "quic_channel_local.h"
14 #include "../ssl_local.h"
15
16 /*
17 * QUIC Port Structure
18 * ===================
19 */
20 #define INIT_DCID_LEN 8
21
22 static int port_init(QUIC_PORT *port);
23 static void port_cleanup(QUIC_PORT *port);
24 static OSSL_TIME get_time(void *arg);
25 static void port_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags);
26 static void port_default_packet_handler(QUIC_URXE *e, void *arg);
27
28 DEFINE_LIST_OF_IMPL(ch, QUIC_CHANNEL);
29
30 QUIC_PORT *ossl_quic_port_new(const QUIC_PORT_ARGS *args)
31 {
32 QUIC_PORT *port;
33
34 if ((port = OPENSSL_zalloc(sizeof(QUIC_PORT))) == NULL)
35 return NULL;
36
37 port->libctx = args->libctx;
38 port->propq = args->propq;
39 port->mutex = args->mutex;
40 port->now_cb = args->now_cb;
41 port->now_cb_arg = args->now_cb_arg;
42 port->channel_ctx = args->channel_ctx;
43 port->is_multi_conn = args->is_multi_conn;
44
45 if (!port_init(port)) {
46 OPENSSL_free(port);
47 return NULL;
48 }
49
50 return port;
51 }
52
53 void ossl_quic_port_free(QUIC_PORT *port)
54 {
55 if (port == NULL)
56 return;
57
58 port_cleanup(port);
59 OPENSSL_free(port);
60 }
61
62 static int port_init(QUIC_PORT *port)
63 {
64 size_t rx_short_dcid_len = (port->is_multi_conn ? INIT_DCID_LEN : 0);
65
66 if (port->channel_ctx == NULL)
67 goto err;
68
69 if ((port->demux = ossl_quic_demux_new(/*BIO=*/NULL,
70 /*Short CID Len=*/rx_short_dcid_len,
71 get_time, port)) == NULL)
72 goto err;
73
74 /*
75 * If we are a server, setup our handler for packets not corresponding to
76 * any known DCID on our end. This is for handling clients establishing new
77 * connections.
78 */
79 // if (is_server)
80 ossl_quic_demux_set_default_handler(port->demux,
81 port_default_packet_handler,
82 port);
83
84 ossl_quic_reactor_init(&port->rtor, port_tick, port, ossl_time_zero());
85 port->rx_short_dcid_len = (unsigned char)rx_short_dcid_len;
86 port->tx_init_dcid_len = INIT_DCID_LEN;
87 return 1;
88
89 err:
90 port_cleanup(port);
91 return 0;
92 }
93
94 static void port_cleanup(QUIC_PORT *port)
95 {
96 assert(ossl_list_ch_num(&port->channel_list) == 0);
97 ossl_quic_demux_free(port->demux);
98 port->demux = NULL;
99 }
100
101 QUIC_REACTOR *ossl_quic_port_get0_reactor(QUIC_PORT *port)
102 {
103 return &port->rtor;
104 }
105
106 QUIC_DEMUX *ossl_quic_port_get0_demux(QUIC_PORT *port)
107 {
108 return port->demux;
109 }
110
111 CRYPTO_MUTEX *ossl_quic_port_get0_mutex(QUIC_PORT *port)
112 {
113 return port->mutex;
114 }
115
116 OSSL_TIME ossl_quic_port_get_time(QUIC_PORT *port)
117 {
118 if (port->now_cb == NULL)
119 return ossl_time_now();
120
121 return port->now_cb(port->now_cb_arg);
122 }
123
124 static OSSL_TIME get_time(void *port)
125 {
126 return ossl_quic_port_get_time(port);
127 }
128
129 int ossl_quic_port_get_rx_short_dcid_len(const QUIC_PORT *port)
130 {
131 return port->rx_short_dcid_len;
132 }
133
134 int ossl_quic_port_get_tx_init_dcid_len(const QUIC_PORT *port)
135 {
136 return port->tx_init_dcid_len;
137 }
138
139 /*
140 * QUIC Port: Network BIO Configuration
141 * ====================================
142 */
143
144 /* Determines whether we can support a given poll descriptor. */
145 static int validate_poll_descriptor(const BIO_POLL_DESCRIPTOR *d)
146 {
147 if (d->type == BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD && d->value.fd < 0) {
148 ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);
149 return 0;
150 }
151
152 return 1;
153 }
154
155 BIO *ossl_quic_port_get_net_rbio(QUIC_PORT *port)
156 {
157 return port->net_rbio;
158 }
159
160 BIO *ossl_quic_port_get_net_wbio(QUIC_PORT *port)
161 {
162 return port->net_wbio;
163 }
164
165 static int port_update_poll_desc(QUIC_PORT *port, BIO *net_bio, int for_write)
166 {
167 BIO_POLL_DESCRIPTOR d = {0};
168
169 if (net_bio == NULL
170 || (!for_write && !BIO_get_rpoll_descriptor(net_bio, &d))
171 || (for_write && !BIO_get_wpoll_descriptor(net_bio, &d)))
172 /* Non-pollable BIO */
173 d.type = BIO_POLL_DESCRIPTOR_TYPE_NONE;
174
175 if (!validate_poll_descriptor(&d))
176 return 0;
177
178 if (for_write)
179 ossl_quic_reactor_set_poll_w(&port->rtor, &d);
180 else
181 ossl_quic_reactor_set_poll_r(&port->rtor, &d);
182
183 return 1;
184 }
185
186 int ossl_quic_port_update_poll_descriptors(QUIC_PORT *port)
187 {
188 int ok = 1;
189
190 if (!port_update_poll_desc(port, port->net_rbio, /*for_write=*/0))
191 ok = 0;
192
193 if (!port_update_poll_desc(port, port->net_wbio, /*for_write=*/1))
194 ok = 0;
195
196 return ok;
197 }
198
199 /*
200 * QUIC_PORT does not ref any BIO it is provided with, nor is any ref
201 * transferred to it. The caller (e.g., QUIC_CONNECTION) is responsible for
202 * ensuring the BIO lasts until the channel is freed or the BIO is switched out
203 * for another BIO by a subsequent successful call to this function.
204 */
205 int ossl_quic_port_set_net_rbio(QUIC_PORT *port, BIO *net_rbio)
206 {
207 if (port->net_rbio == net_rbio)
208 return 1;
209
210 if (!port_update_poll_desc(port, net_rbio, /*for_write=*/0))
211 return 0;
212
213 ossl_quic_demux_set_bio(port->demux, net_rbio);
214 port->net_rbio = net_rbio;
215 return 1;
216 }
217
218 int ossl_quic_port_set_net_wbio(QUIC_PORT *port, BIO *net_wbio)
219 {
220 if (port->net_wbio == net_wbio)
221 return 1;
222
223 if (!port_update_poll_desc(port, net_wbio, /*for_write=*/1))
224 return 0;
225
226 //ossl_qtx_set_bio(port->qtx, net_wbio);
227 port->net_wbio = net_wbio;
228 return 1;
229 }
230
231 /*
232 * QUIC Port: Channel Lifecycle
233 * ============================
234 */
235
236 static SSL *port_new_handshake_layer(QUIC_PORT *port)
237 {
238 SSL *tls = NULL;
239 SSL_CONNECTION *tls_conn = NULL;
240
241 tls = ossl_ssl_connection_new_int(port->channel_ctx, TLS_method());
242 if (tls == NULL || (tls_conn = SSL_CONNECTION_FROM_SSL(tls)) == NULL)
243 return NULL;
244
245 /* Override the user_ssl of the inner connection. */
246 tls_conn->s3.flags |= TLS1_FLAGS_QUIC;
247
248 /* Restrict options derived from the SSL_CTX. */
249 tls_conn->options &= OSSL_QUIC_PERMITTED_OPTIONS_CONN;
250 tls_conn->pha_enabled = 0;
251 return tls;
252 }
253
254 static QUIC_CHANNEL *port_make_channel(QUIC_PORT *port, SSL *tls, int is_server)
255 {
256 QUIC_CHANNEL_ARGS args = {0};
257 QUIC_CHANNEL *ch;
258
259 args.port = port;
260 args.is_server = is_server;
261 args.tls = (tls != NULL ? tls : port_new_handshake_layer(port));
262 if (args.tls == NULL)
263 return NULL;
264
265 ch = ossl_quic_channel_new(&args);
266 if (ch == NULL) {
267 if (tls == NULL)
268 SSL_free(args.tls);
269
270 return NULL;
271 }
272
273 return ch;
274 }
275
276 QUIC_CHANNEL *ossl_quic_port_create_outgoing(QUIC_PORT *port, SSL *tls)
277 {
278 return port_make_channel(port, tls, /*is_server=*/0);
279 }
280
281 QUIC_CHANNEL *ossl_quic_port_create_incoming(QUIC_PORT *port, SSL *tls)
282 {
283 QUIC_CHANNEL *ch;
284
285 assert(port->tserver_ch == NULL);
286
287 ch = port_make_channel(port, tls, /*is_server=*/1);
288 port->tserver_ch = ch;
289 return ch;
290 }
291
292 /*
293 * QUIC Port: Ticker-Mutator
294 * =========================
295 */
296
297 /*
298 * The central ticker function called by the reactor. This does everything, or
299 * at least everything network I/O related. Best effort - not allowed to fail
300 * "loudly".
301 */
302 static void port_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags)
303 {
304 /* TODO */
305 }
306
307 /*
308 * Handles an incoming connection request and potentially decides to make a
309 * connection from it. If a new connection is made, the new channel is written
310 * to *new_ch.
311 */
312 static void port_on_new_conn(QUIC_PORT *port, const BIO_ADDR *peer,
313 const QUIC_CONN_ID *scid,
314 const QUIC_CONN_ID *dcid,
315 QUIC_CHANNEL **new_ch)
316 {
317 if (port->tserver_ch != NULL) {
318 /* Specially assign to existing channel */
319 if (!ossl_quic_channel_on_new_conn(port->tserver_ch, peer, scid, dcid))
320 return;
321
322 *new_ch = port->tserver_ch;
323 port->tserver_ch = NULL;
324 return;
325 }
326 }
327
328 /*
329 * This is called by the demux when we get a packet not destined for any known
330 * DCID.
331 */
332 static void port_default_packet_handler(QUIC_URXE *e, void *arg)
333 {
334 QUIC_PORT *port = arg;
335 PACKET pkt;
336 QUIC_PKT_HDR hdr;
337 QUIC_CHANNEL *new_ch = NULL;
338
339 if (port->tserver_ch == NULL)
340 goto undesirable;
341
342 /*
343 * We have got a packet for an unknown DCID. This might be an attempt to
344 * open a new connection.
345 */
346 if (e->data_len < QUIC_MIN_INITIAL_DGRAM_LEN)
347 goto undesirable;
348
349 if (!PACKET_buf_init(&pkt, ossl_quic_urxe_data(e), e->data_len))
350 goto undesirable;
351
352 /*
353 * We set short_conn_id_len to SIZE_MAX here which will cause the decode
354 * operation to fail if we get a 1-RTT packet. This is fine since we only
355 * care about Initial packets.
356 */
357 if (!ossl_quic_wire_decode_pkt_hdr(&pkt, SIZE_MAX, 1, 0, &hdr, NULL))
358 goto undesirable;
359
360 switch (hdr.version) {
361 case QUIC_VERSION_1:
362 break;
363
364 case QUIC_VERSION_NONE:
365 default:
366 /* Unknown version or proactive version negotiation request, bail. */
367 /* TODO(QUIC SERVER): Handle version negotiation on server side */
368 goto undesirable;
369 }
370
371 /*
372 * We only care about Initial packets which might be trying to establish a
373 * connection.
374 */
375 if (hdr.type != QUIC_PKT_TYPE_INITIAL)
376 goto undesirable;
377
378 /*
379 * Try to process this as a valid attempt to initiate a connection.
380 *
381 * We do not register the DCID in the Initial packet we received as
382 * that DCID is not actually used again, thus after provisioning
383 * the new connection and associated Initial keys, we inject the
384 * received packet directly to the new channel's QRX so that it can
385 * process it as a one-time thing, instead of going through the usual
386 * DEMUX DCID-based routing.
387 */
388 port_on_new_conn(port, &e->peer, &hdr.src_conn_id, &hdr.dst_conn_id,
389 &new_ch);
390 if (new_ch != NULL)
391 ossl_qrx_inject_urxe(new_ch->qrx, e);
392
393 return;
394
395 undesirable:
396 ossl_quic_demux_release_urxe(port->demux, e);
397 }