]> git.ipfire.org Git - thirdparty/openssl.git/blame - ssl/quic/quic_tserver.c
Copyright year updates
[thirdparty/openssl.git] / ssl / quic / quic_tserver.c
CommitLineData
51a168b8 1/*
b6461792 2 * Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved.
51a168b8
HL
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_tserver.h"
11#include "internal/quic_channel.h"
12#include "internal/quic_statm.h"
167e5f34 13#include "internal/quic_port.h"
22739cc3 14#include "internal/quic_engine.h"
51a168b8 15#include "internal/common.h"
37f27b91 16#include "internal/time.h"
cb931288 17#include "quic_local.h"
51a168b8
HL
18
19/*
20 * QUIC Test Server Module
21 * =======================
22 */
23struct quic_tserver_st {
24 QUIC_TSERVER_ARGS args;
25
cb931288
MC
26 /* Dummy SSL object for this QUIC connection for use by msg_callback */
27 SSL *ssl;
28
51a168b8 29 /*
22739cc3 30 * The QUIC engine, port and channel providing the core QUIC connection
167e5f34 31 * implementation.
51a168b8 32 */
22739cc3 33 QUIC_ENGINE *engine;
167e5f34 34 QUIC_PORT *port;
51a168b8
HL
35 QUIC_CHANNEL *ch;
36
e053505f 37 /* The mutex we give to the QUIC channel. */
c4208a6a 38 CRYPTO_MUTEX *mutex;
e053505f 39
4e3a55fd
MC
40 /* SSL_CTX for creating the underlying TLS connection */
41 SSL_CTX *ctx;
42
43 /* SSL for the underlying TLS connection */
44 SSL *tls;
45
51a168b8
HL
46 /* The current peer L4 address. AF_UNSPEC if we do not have a peer yet. */
47 BIO_ADDR cur_peer_addr;
48
49 /* Are we connected to a peer? */
50 unsigned int connected : 1;
51};
52
4e3a55fd
MC
53static int alpn_select_cb(SSL *ssl, const unsigned char **out,
54 unsigned char *outlen, const unsigned char *in,
55 unsigned int inlen, void *arg)
56{
37f27b91
MC
57 QUIC_TSERVER *srv = arg;
58 static const unsigned char alpndeflt[] = {
59 8, 'o', 's', 's', 'l', 't', 'e', 's', 't'
60 };
eadebcc8 61 const unsigned char *alpn;
37f27b91
MC
62 size_t alpnlen;
63
64 if (srv->args.alpn == NULL) {
65 alpn = alpndeflt;
66 alpnlen = sizeof(alpn);
67 } else {
68 alpn = srv->args.alpn;
69 alpnlen = srv->args.alpnlen;
70 }
4e3a55fd 71
37f27b91 72 if (SSL_select_next_proto((unsigned char **)out, outlen, alpn, alpnlen,
4e3a55fd
MC
73 in, inlen) != OPENSSL_NPN_NEGOTIATED)
74 return SSL_TLSEXT_ERR_ALERT_FATAL;
75
76 return SSL_TLSEXT_ERR_OK;
77}
78
79QUIC_TSERVER *ossl_quic_tserver_new(const QUIC_TSERVER_ARGS *args,
80 const char *certfile, const char *keyfile)
51a168b8
HL
81{
82 QUIC_TSERVER *srv = NULL;
22739cc3 83 QUIC_ENGINE_ARGS engine_args = {0};
167e5f34 84 QUIC_PORT_ARGS port_args = {0};
cb931288 85 QUIC_CONNECTION *qc = NULL;
51a168b8
HL
86
87 if (args->net_rbio == NULL || args->net_wbio == NULL)
88 goto err;
89
90 if ((srv = OPENSSL_zalloc(sizeof(*srv))) == NULL)
91 goto err;
92
93 srv->args = *args;
94
629b408c 95#if defined(OPENSSL_THREADS)
9cf091a3 96 if ((srv->mutex = ossl_crypto_mutex_new()) == NULL)
e053505f 97 goto err;
629b408c 98#endif
e053505f 99
829eec9f
MC
100 if (args->ctx != NULL)
101 srv->ctx = args->ctx;
102 else
103 srv->ctx = SSL_CTX_new_ex(srv->args.libctx, srv->args.propq,
104 TLS_method());
4e3a55fd
MC
105 if (srv->ctx == NULL)
106 goto err;
107
1e4fc0b2
MC
108 if (certfile != NULL
109 && SSL_CTX_use_certificate_file(srv->ctx, certfile, SSL_FILETYPE_PEM) <= 0)
4e3a55fd
MC
110 goto err;
111
1e4fc0b2
MC
112 if (keyfile != NULL
113 && SSL_CTX_use_PrivateKey_file(srv->ctx, keyfile, SSL_FILETYPE_PEM) <= 0)
4e3a55fd
MC
114 goto err;
115
116 SSL_CTX_set_alpn_select_cb(srv->ctx, alpn_select_cb, srv);
117
118 srv->tls = SSL_new(srv->ctx);
119 if (srv->tls == NULL)
120 goto err;
121
22739cc3
HL
122 engine_args.libctx = srv->args.libctx;
123 engine_args.propq = srv->args.propq;
124 engine_args.mutex = srv->mutex;
125 engine_args.now_cb = srv->args.now_cb;
126 engine_args.now_cb_arg = srv->args.now_cb_arg;
167e5f34 127
22739cc3
HL
128 if ((srv->engine = ossl_quic_engine_new(&engine_args)) == NULL)
129 goto err;
130
131 port_args.channel_ctx = srv->ctx;
132 port_args.is_multi_conn = 1;
133
134 if ((srv->port = ossl_quic_engine_create_port(srv->engine, &port_args)) == NULL)
167e5f34
HL
135 goto err;
136
2d80e459 137 if ((srv->ch = ossl_quic_port_create_incoming(srv->port, srv->tls)) == NULL)
51a168b8
HL
138 goto err;
139
073e5bc7
HL
140 if (!ossl_quic_port_set_net_rbio(srv->port, srv->args.net_rbio)
141 || !ossl_quic_port_set_net_wbio(srv->port, srv->args.net_wbio))
51a168b8
HL
142 goto err;
143
cb931288
MC
144 qc = OPENSSL_zalloc(sizeof(*qc));
145 if (qc == NULL)
146 goto err;
147 srv->ssl = (SSL *)qc;
148 qc->ch = srv->ch;
149 srv->ssl->type = SSL_TYPE_QUIC_CONNECTION;
150
51a168b8
HL
151 return srv;
152
153err:
9cf091a3 154 if (srv != NULL) {
829eec9f
MC
155 if (args->ctx == NULL)
156 SSL_CTX_free(srv->ctx);
157 SSL_free(srv->tls);
51a168b8 158 ossl_quic_channel_free(srv->ch);
167e5f34 159 ossl_quic_port_free(srv->port);
22739cc3 160 ossl_quic_engine_free(srv->engine);
629b408c 161#if defined(OPENSSL_THREADS)
9cf091a3 162 ossl_crypto_mutex_free(&srv->mutex);
629b408c 163#endif
cb931288 164 OPENSSL_free(qc);
9cf091a3 165 }
51a168b8
HL
166
167 OPENSSL_free(srv);
168 return NULL;
169}
170
171void ossl_quic_tserver_free(QUIC_TSERVER *srv)
172{
173 if (srv == NULL)
174 return;
175
fa4b1151 176 SSL_free(srv->tls);
51a168b8 177 ossl_quic_channel_free(srv->ch);
167e5f34 178 ossl_quic_port_free(srv->port);
22739cc3 179 ossl_quic_engine_free(srv->engine);
18fd0ea0
MC
180 BIO_free_all(srv->args.net_rbio);
181 BIO_free_all(srv->args.net_wbio);
cb931288 182 OPENSSL_free(srv->ssl);
4e3a55fd 183 SSL_CTX_free(srv->ctx);
629b408c 184#if defined(OPENSSL_THREADS)
9cf091a3 185 ossl_crypto_mutex_free(&srv->mutex);
629b408c 186#endif
51a168b8
HL
187 OPENSSL_free(srv);
188}
189
14e31409 190/* Set mutator callbacks for test framework support */
d03fe5de
MC
191int ossl_quic_tserver_set_plain_packet_mutator(QUIC_TSERVER *srv,
192 ossl_mutate_packet_cb mutatecb,
193 ossl_finish_mutate_cb finishmutatecb,
194 void *mutatearg)
14e31409
MC
195{
196 return ossl_quic_channel_set_mutator(srv->ch, mutatecb, finishmutatecb,
197 mutatearg);
198}
199
d03fe5de
MC
200int ossl_quic_tserver_set_handshake_mutator(QUIC_TSERVER *srv,
201 ossl_statem_mutate_handshake_cb mutate_handshake_cb,
202 ossl_statem_finish_mutate_handshake_cb finish_mutate_handshake_cb,
203 void *mutatearg)
204{
205 return ossl_statem_set_mutator(ossl_quic_channel_get0_ssl(srv->ch),
206 mutate_handshake_cb,
207 finish_mutate_handshake_cb,
208 mutatearg);
209}
210
51a168b8
HL
211int ossl_quic_tserver_tick(QUIC_TSERVER *srv)
212{
ccd31037 213 ossl_quic_reactor_tick(ossl_quic_channel_get_reactor(srv->ch), 0);
51a168b8
HL
214
215 if (ossl_quic_channel_is_active(srv->ch))
216 srv->connected = 1;
217
218 return 1;
219}
220
dbe7b51a
HL
221int ossl_quic_tserver_is_connected(QUIC_TSERVER *srv)
222{
223 return ossl_quic_channel_is_active(srv->ch);
224}
225
adef87a2 226/* Returns 1 if the server is in any terminating or terminated state */
45bb98bf 227int ossl_quic_tserver_is_term_any(const QUIC_TSERVER *srv)
adef87a2 228{
c12e1113
MC
229 return ossl_quic_channel_is_term_any(srv->ch);
230}
231
723cbe8a
HL
232const QUIC_TERMINATE_CAUSE *
233ossl_quic_tserver_get_terminate_cause(const QUIC_TSERVER *srv)
c12e1113
MC
234{
235 return ossl_quic_channel_get_terminate_cause(srv->ch);
149a8e6c
MC
236}
237
238/* Returns 1 if the server is in a terminated state */
45bb98bf 239int ossl_quic_tserver_is_terminated(const QUIC_TSERVER *srv)
149a8e6c 240{
c12e1113 241 return ossl_quic_channel_is_terminated(srv->ch);
adef87a2
MC
242}
243
45bb98bf 244int ossl_quic_tserver_is_handshake_confirmed(const QUIC_TSERVER *srv)
f10e5885 245{
ce8f20b6 246 return ossl_quic_channel_is_handshake_confirmed(srv->ch);
f10e5885
MC
247}
248
51a168b8 249int ossl_quic_tserver_read(QUIC_TSERVER *srv,
b757beb5 250 uint64_t stream_id,
51a168b8
HL
251 unsigned char *buf,
252 size_t buf_len,
253 size_t *bytes_read)
254{
a9979965 255 int is_fin = 0;
b757beb5 256 QUIC_STREAM *qs;
51a168b8 257
b757beb5
HL
258 qs = ossl_quic_stream_map_get_by_id(ossl_quic_channel_get_qsm(srv->ch),
259 stream_id);
260 if (qs == NULL) {
261 int is_client_init
262 = ((stream_id & QUIC_STREAM_INITIATOR_MASK)
263 == QUIC_STREAM_INITIATOR_CLIENT);
264
265 /*
266 * A client-initiated stream might spontaneously come into existence, so
5904a0a7
HL
267 * allow trying to read on a client-initiated stream before it exists,
268 * assuming the connection is still active.
b757beb5
HL
269 * Otherwise, fail.
270 */
5904a0a7 271 if (!is_client_init || !ossl_quic_channel_is_active(srv->ch))
b757beb5
HL
272 return 0;
273
274 *bytes_read = 0;
275 return 1;
276 }
277
5ed3a435
HL
278 if (qs->recv_state == QUIC_RSTREAM_STATE_DATA_READ
279 || !ossl_quic_stream_has_recv_buffer(qs))
a9979965
HL
280 return 0;
281
b757beb5 282 if (!ossl_quic_rstream_read(qs->rstream, buf, buf_len,
51a168b8
HL
283 bytes_read, &is_fin))
284 return 0;
285
286 if (*bytes_read > 0) {
287 /*
288 * We have read at least one byte from the stream. Inform stream-level
289 * RXFC of the retirement of controlled bytes. Update the active stream
290 * status (the RXFC may now want to emit a frame granting more credit to
291 * the peer).
292 */
293 OSSL_RTT_INFO rtt_info;
091f532e 294
51a168b8
HL
295 ossl_statm_get_rtt_info(ossl_quic_channel_get_statm(srv->ch), &rtt_info);
296
b757beb5 297 if (!ossl_quic_rxfc_on_retire(&qs->rxfc, *bytes_read,
51a168b8
HL
298 rtt_info.smoothed_rtt))
299 return 0;
300 }
301
302 if (is_fin)
5ed3a435
HL
303 ossl_quic_stream_map_notify_totally_read(ossl_quic_channel_get_qsm(srv->ch),
304 qs);
51a168b8
HL
305
306 if (*bytes_read > 0)
b757beb5 307 ossl_quic_stream_map_update_state(ossl_quic_channel_get_qsm(srv->ch), qs);
51a168b8
HL
308
309 return 1;
310}
311
b757beb5 312int ossl_quic_tserver_has_read_ended(QUIC_TSERVER *srv, uint64_t stream_id)
a9979965 313{
b757beb5 314 QUIC_STREAM *qs;
22894016
HL
315 unsigned char buf[1];
316 size_t bytes_read = 0;
317 int is_fin = 0;
b757beb5
HL
318
319 qs = ossl_quic_stream_map_get_by_id(ossl_quic_channel_get_qsm(srv->ch),
320 stream_id);
321
5ed3a435 322 if (qs == NULL)
22894016
HL
323 return 0;
324
5ed3a435 325 if (qs->recv_state == QUIC_RSTREAM_STATE_DATA_READ)
22894016
HL
326 return 1;
327
5ed3a435
HL
328 if (!ossl_quic_stream_has_recv_buffer(qs))
329 return 0;
330
22894016 331 /*
5ed3a435
HL
332 * If we do not have the DATA_READ, it is possible we should still return 1
333 * if there is a lone FIN (but no more data) remaining to be retired from
22894016
HL
334 * the RSTREAM, for example because ossl_quic_tserver_read() has not been
335 * called since the FIN was received.
336 */
337 if (!ossl_quic_rstream_peek(qs->rstream, buf, sizeof(buf),
338 &bytes_read, &is_fin))
339 return 0;
340
341 if (is_fin && bytes_read == 0) {
342 /* If we have a FIN awaiting retirement and no data before it... */
343 /* Let RSTREAM know we've consumed this FIN. */
f540b6b4 344 if (!ossl_quic_rstream_read(qs->rstream, buf, sizeof(buf),
f2609004
HL
345 &bytes_read, &is_fin))
346 return 0;
f540b6b4 347
22894016 348 assert(is_fin && bytes_read == 0);
5ed3a435 349 assert(qs->recv_state == QUIC_RSTREAM_STATE_DATA_RECVD);
22894016 350
5ed3a435
HL
351 ossl_quic_stream_map_notify_totally_read(ossl_quic_channel_get_qsm(srv->ch),
352 qs);
22894016
HL
353 ossl_quic_stream_map_update_state(ossl_quic_channel_get_qsm(srv->ch), qs);
354 return 1;
355 }
356
357 return 0;
a9979965
HL
358}
359
51a168b8 360int ossl_quic_tserver_write(QUIC_TSERVER *srv,
b757beb5 361 uint64_t stream_id,
51a168b8
HL
362 const unsigned char *buf,
363 size_t buf_len,
364 size_t *bytes_written)
365{
b757beb5
HL
366 QUIC_STREAM *qs;
367
51a168b8
HL
368 if (!ossl_quic_channel_is_active(srv->ch))
369 return 0;
370
b757beb5
HL
371 qs = ossl_quic_stream_map_get_by_id(ossl_quic_channel_get_qsm(srv->ch),
372 stream_id);
2f018d14 373 if (qs == NULL || !ossl_quic_stream_has_send_buffer(qs))
b757beb5
HL
374 return 0;
375
376 if (!ossl_quic_sstream_append(qs->sstream,
51a168b8
HL
377 buf, buf_len, bytes_written))
378 return 0;
379
380 if (*bytes_written > 0)
381 /*
382 * We have appended at least one byte to the stream. Potentially mark
383 * the stream as active, depending on FC.
384 */
b757beb5 385 ossl_quic_stream_map_update_state(ossl_quic_channel_get_qsm(srv->ch), qs);
51a168b8
HL
386
387 /* Try and send. */
388 ossl_quic_tserver_tick(srv);
389 return 1;
390}
a9979965 391
b757beb5 392int ossl_quic_tserver_conclude(QUIC_TSERVER *srv, uint64_t stream_id)
a9979965 393{
b757beb5
HL
394 QUIC_STREAM *qs;
395
a9979965
HL
396 if (!ossl_quic_channel_is_active(srv->ch))
397 return 0;
398
b757beb5
HL
399 qs = ossl_quic_stream_map_get_by_id(ossl_quic_channel_get_qsm(srv->ch),
400 stream_id);
2f018d14 401 if (qs == NULL || !ossl_quic_stream_has_send_buffer(qs))
b757beb5
HL
402 return 0;
403
404 if (!ossl_quic_sstream_get_final_size(qs->sstream, NULL)) {
405 ossl_quic_sstream_fin(qs->sstream);
406 ossl_quic_stream_map_update_state(ossl_quic_channel_get_qsm(srv->ch), qs);
a9979965
HL
407 }
408
409 ossl_quic_tserver_tick(srv);
410 return 1;
411}
0c593328 412
b757beb5
HL
413int ossl_quic_tserver_stream_new(QUIC_TSERVER *srv,
414 int is_uni,
415 uint64_t *stream_id)
416{
417 QUIC_STREAM *qs;
418
419 if (!ossl_quic_channel_is_active(srv->ch))
420 return 0;
421
422 if ((qs = ossl_quic_channel_new_stream_local(srv->ch, is_uni)) == NULL)
423 return 0;
424
425 *stream_id = qs->id;
426 return 1;
427}
428
0c593328
MC
429BIO *ossl_quic_tserver_get0_rbio(QUIC_TSERVER *srv)
430{
431 return srv->args.net_rbio;
432}
f0e22d1b 433
829eec9f
MC
434SSL_CTX *ossl_quic_tserver_get0_ssl_ctx(QUIC_TSERVER *srv)
435{
436 return srv->ctx;
437}
438
f0e22d1b
HL
439int ossl_quic_tserver_stream_has_peer_stop_sending(QUIC_TSERVER *srv,
440 uint64_t stream_id,
441 uint64_t *app_error_code)
442{
443 QUIC_STREAM *qs;
444
445 qs = ossl_quic_stream_map_get_by_id(ossl_quic_channel_get_qsm(srv->ch),
446 stream_id);
447 if (qs == NULL)
448 return 0;
449
450 if (qs->peer_stop_sending && app_error_code != NULL)
451 *app_error_code = qs->peer_stop_sending_aec;
452
453 return qs->peer_stop_sending;
454}
455
456int ossl_quic_tserver_stream_has_peer_reset_stream(QUIC_TSERVER *srv,
457 uint64_t stream_id,
458 uint64_t *app_error_code)
459{
460 QUIC_STREAM *qs;
461
462 qs = ossl_quic_stream_map_get_by_id(ossl_quic_channel_get_qsm(srv->ch),
463 stream_id);
464 if (qs == NULL)
465 return 0;
466
2f018d14 467 if (ossl_quic_stream_recv_is_reset(qs) && app_error_code != NULL)
f0e22d1b
HL
468 *app_error_code = qs->peer_reset_stream_aec;
469
2f018d14 470 return ossl_quic_stream_recv_is_reset(qs);
f0e22d1b 471}
80b9eca2
TM
472
473int ossl_quic_tserver_set_new_local_cid(QUIC_TSERVER *srv,
474 const QUIC_CONN_ID *conn_id)
475{
476 /* Replace existing local connection ID in the QUIC_CHANNEL */
477 return ossl_quic_channel_replace_local_cid(srv->ch, conn_id);
478}
1df479a9
HL
479
480uint64_t ossl_quic_tserver_pop_incoming_stream(QUIC_TSERVER *srv)
481{
482 QUIC_STREAM_MAP *qsm = ossl_quic_channel_get_qsm(srv->ch);
483 QUIC_STREAM *qs = ossl_quic_stream_map_peek_accept_queue(qsm);
484
485 if (qs == NULL)
486 return UINT64_MAX;
487
488 ossl_quic_stream_map_remove_from_accept_queue(qsm, qs, ossl_time_zero());
489
490 return qs->id;
491}
37f27b91
MC
492
493int ossl_quic_tserver_is_stream_totally_acked(QUIC_TSERVER *srv,
494 uint64_t stream_id)
495{
496 QUIC_STREAM *qs;
497
498 qs = ossl_quic_stream_map_get_by_id(ossl_quic_channel_get_qsm(srv->ch),
499 stream_id);
500 if (qs == NULL)
501 return 1;
502
503 return ossl_quic_sstream_is_totally_acked(qs->sstream);
504}
505
506int ossl_quic_tserver_get_net_read_desired(QUIC_TSERVER *srv)
507{
508 return ossl_quic_reactor_net_read_desired(
509 ossl_quic_channel_get_reactor(srv->ch));
510}
511
512int ossl_quic_tserver_get_net_write_desired(QUIC_TSERVER *srv)
513{
514 return ossl_quic_reactor_net_write_desired(
515 ossl_quic_channel_get_reactor(srv->ch));
516}
517
518OSSL_TIME ossl_quic_tserver_get_deadline(QUIC_TSERVER *srv)
519{
520 return ossl_quic_reactor_get_tick_deadline(
521 ossl_quic_channel_get_reactor(srv->ch));
522}
523
3bc38ba0 524int ossl_quic_tserver_shutdown(QUIC_TSERVER *srv, uint64_t app_error_code)
37f27b91 525{
3bc38ba0 526 ossl_quic_channel_local_close(srv->ch, app_error_code, NULL);
37f27b91 527
8e520d27 528 /* TODO(QUIC SERVER): !SSL_SHUTDOWN_FLAG_NO_STREAM_FLUSH */
37f27b91
MC
529
530 if (ossl_quic_channel_is_terminated(srv->ch))
531 return 1;
532
533 ossl_quic_reactor_tick(ossl_quic_channel_get_reactor(srv->ch), 0);
534
535 return ossl_quic_channel_is_terminated(srv->ch);
536}
9ff3a99e
HL
537
538int ossl_quic_tserver_ping(QUIC_TSERVER *srv)
539{
f36504cc
HL
540 if (ossl_quic_channel_is_terminated(srv->ch))
541 return 0;
9ff3a99e
HL
542
543 if (!ossl_quic_channel_ping(srv->ch))
f36504cc 544 return 0;
9ff3a99e
HL
545
546 ossl_quic_reactor_tick(ossl_quic_channel_get_reactor(srv->ch), 0);
547 return 1;
548}
7eb330ff 549
17340e87
HL
550QUIC_CHANNEL *ossl_quic_tserver_get_channel(QUIC_TSERVER *srv)
551{
552 return srv->ch;
553}
554
7eb330ff
HL
555void ossl_quic_tserver_set_msg_callback(QUIC_TSERVER *srv,
556 void (*f)(int write_p, int version,
557 int content_type,
558 const void *buf, size_t len,
559 SSL *ssl, void *arg),
560 void *arg)
561{
cb931288 562 ossl_quic_channel_set_msg_callback(srv->ch, f, srv->ssl);
7eb330ff 563 ossl_quic_channel_set_msg_callback_arg(srv->ch, arg);
cb931288
MC
564 SSL_set_msg_callback(srv->tls, f);
565 SSL_set_msg_callback_arg(srv->tls, arg);
7eb330ff 566}
614c08c2
MC
567
568int ossl_quic_tserver_new_ticket(QUIC_TSERVER *srv)
569{
570 return SSL_new_session_ticket(srv->tls);
571}
644ef0bb
MC
572
573int ossl_quic_tserver_set_max_early_data(QUIC_TSERVER *srv,
574 uint32_t max_early_data)
575{
576 return SSL_set_max_early_data(srv->tls, max_early_data);
577}
1e4fc0b2
MC
578
579void ossl_quic_tserver_set_psk_find_session_cb(QUIC_TSERVER *srv,
580 SSL_psk_find_session_cb_func cb)
581{
582 SSL_set_psk_find_session_callback(srv->tls, cb);
583}