]> git.ipfire.org Git - thirdparty/openssl.git/blob - test/helpers/quictestlib.c
QUIC: Automatically drain non-concluded streams, bugfixes
[thirdparty/openssl.git] / test / helpers / quictestlib.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
10 #include <assert.h>
11 #include <openssl/configuration.h>
12 #include <openssl/bio.h>
13 #include "quictestlib.h"
14 #include "ssltestlib.h"
15 #include "../testutil.h"
16 #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
17 # include "../threadstest.h"
18 #endif
19 #include "internal/quic_wire_pkt.h"
20 #include "internal/quic_record_tx.h"
21 #include "internal/quic_error.h"
22 #include "internal/packet.h"
23
24 #define GROWTH_ALLOWANCE 1024
25
26 struct qtest_fault {
27 QUIC_TSERVER *qtserv;
28
29 /* Plain packet mutations */
30 /* Header for the plaintext packet */
31 QUIC_PKT_HDR pplainhdr;
32 /* iovec for the plaintext packet data buffer */
33 OSSL_QTX_IOVEC pplainio;
34 /* Allocated size of the plaintext packet data buffer */
35 size_t pplainbuf_alloc;
36 qtest_fault_on_packet_plain_cb pplaincb;
37 void *pplaincbarg;
38
39 /* Handshake message mutations */
40 /* Handshake message buffer */
41 unsigned char *handbuf;
42 /* Allocated size of the handshake message buffer */
43 size_t handbufalloc;
44 /* Actual length of the handshake message */
45 size_t handbuflen;
46 qtest_fault_on_handshake_cb handshakecb;
47 void *handshakecbarg;
48 qtest_fault_on_enc_ext_cb encextcb;
49 void *encextcbarg;
50
51 /* Cipher packet mutations */
52 qtest_fault_on_packet_cipher_cb pciphercb;
53 void *pciphercbarg;
54
55 /* Datagram mutations */
56 qtest_fault_on_datagram_cb datagramcb;
57 void *datagramcbarg;
58 /* The currently processed message */
59 BIO_MSG msg;
60 /* Allocated size of msg data buffer */
61 size_t msgalloc;
62 };
63
64 static void packet_plain_finish(void *arg);
65 static void handshake_finish(void *arg);
66
67 static OSSL_TIME fake_now;
68
69 static OSSL_TIME fake_now_cb(void *arg)
70 {
71 return fake_now;
72 }
73
74 int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx,
75 char *certfile, char *keyfile,
76 int flags, QUIC_TSERVER **qtserv, SSL **cssl,
77 QTEST_FAULT **fault)
78 {
79 /* ALPN value as recognised by QUIC_TSERVER */
80 unsigned char alpn[] = { 8, 'o', 's', 's', 'l', 't', 'e', 's', 't' };
81 QUIC_TSERVER_ARGS tserver_args = {0};
82 BIO *cbio = NULL, *sbio = NULL, *fisbio = NULL;
83 BIO_ADDR *peeraddr = NULL;
84 struct in_addr ina = {0};
85
86 *qtserv = NULL;
87 if (fault != NULL)
88 *fault = NULL;
89
90 if (*cssl == NULL) {
91 *cssl = SSL_new(clientctx);
92 if (!TEST_ptr(*cssl))
93 return 0;
94 }
95
96 /* SSL_set_alpn_protos returns 0 for success! */
97 if (!TEST_false(SSL_set_alpn_protos(*cssl, alpn, sizeof(alpn))))
98 goto err;
99
100 if (!TEST_ptr(peeraddr = BIO_ADDR_new()))
101 goto err;
102
103 if ((flags & QTEST_FLAG_BLOCK) != 0) {
104 #if !defined(OPENSSL_NO_POSIX_IO)
105 int cfd, sfd;
106
107 /*
108 * For blocking mode we need to create actual sockets rather than doing
109 * everything in memory
110 */
111 if (!TEST_true(create_test_sockets(&cfd, &sfd, SOCK_DGRAM, peeraddr)))
112 goto err;
113 cbio = BIO_new_dgram(cfd, 1);
114 if (!TEST_ptr(cbio)) {
115 close(cfd);
116 close(sfd);
117 goto err;
118 }
119 sbio = BIO_new_dgram(sfd, 1);
120 if (!TEST_ptr(sbio)) {
121 close(sfd);
122 goto err;
123 }
124 #else
125 goto err;
126 #endif
127 } else {
128 if (!TEST_true(BIO_new_bio_dgram_pair(&cbio, 0, &sbio, 0)))
129 goto err;
130
131 if (!TEST_true(BIO_dgram_set_caps(cbio, BIO_DGRAM_CAP_HANDLES_DST_ADDR))
132 || !TEST_true(BIO_dgram_set_caps(sbio, BIO_DGRAM_CAP_HANDLES_DST_ADDR)))
133 goto err;
134
135 /* Dummy server address */
136 if (!TEST_true(BIO_ADDR_rawmake(peeraddr, AF_INET, &ina, sizeof(ina),
137 htons(0))))
138 goto err;
139 }
140
141 SSL_set_bio(*cssl, cbio, cbio);
142
143 if (!TEST_true(SSL_set_blocking_mode(*cssl,
144 (flags & QTEST_FLAG_BLOCK) != 0 ? 1 : 0)))
145 goto err;
146
147 if (!TEST_true(SSL_set_initial_peer_addr(*cssl, peeraddr)))
148 goto err;
149
150 if (fault != NULL) {
151 *fault = OPENSSL_zalloc(sizeof(**fault));
152 if (*fault == NULL)
153 goto err;
154 }
155
156 fisbio = BIO_new(qtest_get_bio_method());
157 if (!TEST_ptr(fisbio))
158 goto err;
159
160 BIO_set_data(fisbio, fault == NULL ? NULL : *fault);
161
162 if (!TEST_ptr(BIO_push(fisbio, sbio)))
163 goto err;
164
165 tserver_args.libctx = libctx;
166 tserver_args.net_rbio = sbio;
167 tserver_args.net_wbio = fisbio;
168 tserver_args.alpn = NULL;
169 if ((flags & QTEST_FLAG_FAKE_TIME) != 0) {
170 fake_now = ossl_time_zero();
171 tserver_args.now_cb = fake_now_cb;
172 }
173
174 if (!TEST_ptr(*qtserv = ossl_quic_tserver_new(&tserver_args, certfile,
175 keyfile)))
176 goto err;
177
178 /* Ownership of fisbio and sbio is now held by *qtserv */
179 sbio = NULL;
180 fisbio = NULL;
181
182 if (fault != NULL)
183 (*fault)->qtserv = *qtserv;
184
185 BIO_ADDR_free(peeraddr);
186
187 return 1;
188 err:
189 BIO_ADDR_free(peeraddr);
190 BIO_free(cbio);
191 BIO_free(fisbio);
192 BIO_free(sbio);
193 SSL_free(*cssl);
194 *cssl = NULL;
195 ossl_quic_tserver_free(*qtserv);
196 if (fault != NULL)
197 OPENSSL_free(*fault);
198
199 return 0;
200 }
201
202 void qtest_add_time(uint64_t millis)
203 {
204 fake_now = ossl_time_add(fake_now, ossl_ms2time(millis));
205 }
206
207 QTEST_FAULT *qtest_create_injector(QUIC_TSERVER *ts)
208 {
209 QTEST_FAULT *f;
210
211 f = OPENSSL_zalloc(sizeof(*f));
212 if (f == NULL)
213 return NULL;
214
215 f->qtserv = ts;
216 return f;
217
218 }
219
220 int qtest_supports_blocking(void)
221 {
222 #if !defined(OPENSSL_NO_POSIX_IO) && defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
223 return 1;
224 #else
225 return 0;
226 #endif
227 }
228
229 #define MAXLOOPS 1000
230
231 #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
232 static int globserverret = 0;
233 static QUIC_TSERVER *globtserv;
234 static const thread_t thread_zero;
235
236 static void run_server_thread(void)
237 {
238 /*
239 * This will operate in a busy loop because the server does not block,
240 * but should be acceptable because it is local and we expect this to be
241 * fast
242 */
243 globserverret = qtest_create_quic_connection(globtserv, NULL);
244 }
245 #endif
246
247 int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl)
248 {
249 int retc = -1, rets = 0, err, abortctr = 0, ret = 0;
250 int clienterr = 0, servererr = 0;
251 #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
252 /*
253 * Pointless initialisation to avoid bogus compiler warnings about using
254 * t uninitialised
255 */
256 thread_t t = thread_zero;
257 #endif
258
259 if (!TEST_ptr(qtserv)) {
260 goto err;
261 } else if (clientssl == NULL) {
262 retc = 1;
263 } else if (SSL_get_blocking_mode(clientssl) > 0) {
264 #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
265 /*
266 * clientssl is blocking. We will need a thread to complete the
267 * connection
268 */
269 globtserv = qtserv;
270 if (!TEST_true(run_thread(&t, run_server_thread)))
271 goto err;
272
273 qtserv = NULL;
274 rets = 1;
275 #else
276 TEST_error("No thread support in this build");
277 goto err;
278 #endif
279 }
280
281 do {
282 err = SSL_ERROR_WANT_WRITE;
283 while (!clienterr && retc <= 0 && err == SSL_ERROR_WANT_WRITE) {
284 retc = SSL_connect(clientssl);
285 if (retc <= 0)
286 err = SSL_get_error(clientssl, retc);
287 }
288
289 if (!clienterr && retc <= 0 && err != SSL_ERROR_WANT_READ) {
290 TEST_info("SSL_connect() failed %d, %d", retc, err);
291 TEST_openssl_errors();
292 clienterr = 1;
293 }
294
295 /*
296 * We're cheating. We don't take any notice of SSL_get_tick_timeout()
297 * and tick every time around the loop anyway. This is inefficient. We
298 * can get away with it in test code because we control both ends of
299 * the communications and don't expect network delays. This shouldn't
300 * be done in a real application.
301 */
302 if (!clienterr && retc <= 0)
303 SSL_handle_events(clientssl);
304 if (!servererr && rets <= 0) {
305 qtest_add_time(1);
306 ossl_quic_tserver_tick(qtserv);
307 servererr = ossl_quic_tserver_is_term_any(qtserv);
308 if (!servererr)
309 rets = ossl_quic_tserver_is_handshake_confirmed(qtserv);
310 }
311
312 if (clienterr && servererr)
313 goto err;
314
315 if (clientssl != NULL && ++abortctr == MAXLOOPS) {
316 TEST_info("No progress made");
317 goto err;
318 }
319 } while ((retc <= 0 && !clienterr) || (rets <= 0 && !servererr));
320
321 if (qtserv == NULL && rets > 0) {
322 #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
323 if (!TEST_true(wait_for_thread(t)) || !TEST_true(globserverret))
324 goto err;
325 #else
326 TEST_error("Should not happen");
327 goto err;
328 #endif
329 }
330
331 if (!clienterr && !servererr)
332 ret = 1;
333 err:
334 return ret;
335 }
336
337 int qtest_shutdown(QUIC_TSERVER *qtserv, SSL *clientssl)
338 {
339 /* Busy loop in non-blocking mode. It should be quick because its local */
340 for (;;) {
341 int rc = SSL_shutdown(clientssl);
342
343 if (rc == 1)
344 break;
345
346 if (rc < 0)
347 return 0;
348
349 ossl_quic_tserver_tick(qtserv);
350 }
351
352 return 1;
353 }
354
355 int qtest_check_server_transport_err(QUIC_TSERVER *qtserv, uint64_t code)
356 {
357 const QUIC_TERMINATE_CAUSE *cause;
358
359 ossl_quic_tserver_tick(qtserv);
360
361 /*
362 * Check that the server has closed with the specified code from the client
363 */
364 if (!TEST_true(ossl_quic_tserver_is_term_any(qtserv)))
365 return 0;
366
367 cause = ossl_quic_tserver_get_terminate_cause(qtserv);
368 if (!TEST_ptr(cause)
369 || !TEST_true(cause->remote)
370 || !TEST_false(cause->app)
371 || !TEST_uint64_t_eq(cause->error_code, code))
372 return 0;
373
374 return 1;
375 }
376
377 int qtest_check_server_protocol_err(QUIC_TSERVER *qtserv)
378 {
379 return qtest_check_server_transport_err(qtserv, QUIC_ERR_PROTOCOL_VIOLATION);
380 }
381
382 int qtest_check_server_frame_encoding_err(QUIC_TSERVER *qtserv)
383 {
384 return qtest_check_server_transport_err(qtserv, QUIC_ERR_FRAME_ENCODING_ERROR);
385 }
386
387 void qtest_fault_free(QTEST_FAULT *fault)
388 {
389 if (fault == NULL)
390 return;
391
392 packet_plain_finish(fault);
393 handshake_finish(fault);
394
395 OPENSSL_free(fault);
396 }
397
398 static int packet_plain_mutate(const QUIC_PKT_HDR *hdrin,
399 const OSSL_QTX_IOVEC *iovecin, size_t numin,
400 QUIC_PKT_HDR **hdrout,
401 const OSSL_QTX_IOVEC **iovecout,
402 size_t *numout,
403 void *arg)
404 {
405 QTEST_FAULT *fault = arg;
406 size_t i, bufsz = 0;
407 unsigned char *cur;
408
409 /* Coalesce our data into a single buffer */
410
411 /* First calculate required buffer size */
412 for (i = 0; i < numin; i++)
413 bufsz += iovecin[i].buf_len;
414
415 fault->pplainio.buf_len = bufsz;
416
417 /* Add an allowance for possible growth */
418 bufsz += GROWTH_ALLOWANCE;
419
420 fault->pplainio.buf = cur = OPENSSL_malloc(bufsz);
421 if (cur == NULL) {
422 fault->pplainio.buf_len = 0;
423 return 0;
424 }
425
426 fault->pplainbuf_alloc = bufsz;
427
428 /* Copy in the data from the input buffers */
429 for (i = 0; i < numin; i++) {
430 memcpy(cur, iovecin[i].buf, iovecin[i].buf_len);
431 cur += iovecin[i].buf_len;
432 }
433
434 fault->pplainhdr = *hdrin;
435
436 /* Cast below is safe because we allocated the buffer */
437 if (fault->pplaincb != NULL
438 && !fault->pplaincb(fault, &fault->pplainhdr,
439 (unsigned char *)fault->pplainio.buf,
440 fault->pplainio.buf_len, fault->pplaincbarg))
441 return 0;
442
443 *hdrout = &fault->pplainhdr;
444 *iovecout = &fault->pplainio;
445 *numout = 1;
446
447 return 1;
448 }
449
450 static void packet_plain_finish(void *arg)
451 {
452 QTEST_FAULT *fault = arg;
453
454 /* Cast below is safe because we allocated the buffer */
455 OPENSSL_free((unsigned char *)fault->pplainio.buf);
456 fault->pplainio.buf_len = 0;
457 fault->pplainbuf_alloc = 0;
458 fault->pplainio.buf = NULL;
459 }
460
461 int qtest_fault_set_packet_plain_listener(QTEST_FAULT *fault,
462 qtest_fault_on_packet_plain_cb pplaincb,
463 void *pplaincbarg)
464 {
465 fault->pplaincb = pplaincb;
466 fault->pplaincbarg = pplaincbarg;
467
468 return ossl_quic_tserver_set_plain_packet_mutator(fault->qtserv,
469 packet_plain_mutate,
470 packet_plain_finish,
471 fault);
472 }
473
474 /* To be called from a packet_plain_listener callback */
475 int qtest_fault_resize_plain_packet(QTEST_FAULT *fault, size_t newlen)
476 {
477 unsigned char *buf;
478 size_t oldlen = fault->pplainio.buf_len;
479
480 /*
481 * Alloc'd size should always be non-zero, so if this fails we've been
482 * incorrectly called
483 */
484 if (fault->pplainbuf_alloc == 0)
485 return 0;
486
487 if (newlen > fault->pplainbuf_alloc) {
488 /* This exceeds our growth allowance. Fail */
489 return 0;
490 }
491
492 /* Cast below is safe because we allocated the buffer */
493 buf = (unsigned char *)fault->pplainio.buf;
494
495 if (newlen > oldlen) {
496 /* Extend packet with 0 bytes */
497 memset(buf + oldlen, 0, newlen - oldlen);
498 } /* else we're truncating or staying the same */
499
500 fault->pplainio.buf_len = newlen;
501 fault->pplainhdr.len = newlen;
502
503 return 1;
504 }
505
506 /*
507 * Prepend frame data into a packet. To be called from a packet_plain_listener
508 * callback
509 */
510 int qtest_fault_prepend_frame(QTEST_FAULT *fault, const unsigned char *frame,
511 size_t frame_len)
512 {
513 unsigned char *buf;
514 size_t old_len;
515
516 /*
517 * Alloc'd size should always be non-zero, so if this fails we've been
518 * incorrectly called
519 */
520 if (fault->pplainbuf_alloc == 0)
521 return 0;
522
523 /* Cast below is safe because we allocated the buffer */
524 buf = (unsigned char *)fault->pplainio.buf;
525 old_len = fault->pplainio.buf_len;
526
527 /* Extend the size of the packet by the size of the new frame */
528 if (!TEST_true(qtest_fault_resize_plain_packet(fault,
529 old_len + frame_len)))
530 return 0;
531
532 memmove(buf + frame_len, buf, old_len);
533 memcpy(buf, frame, frame_len);
534
535 return 1;
536 }
537
538 static int handshake_mutate(const unsigned char *msgin, size_t msginlen,
539 unsigned char **msgout, size_t *msgoutlen,
540 void *arg)
541 {
542 QTEST_FAULT *fault = arg;
543 unsigned char *buf;
544 unsigned long payloadlen;
545 unsigned int msgtype;
546 PACKET pkt;
547
548 buf = OPENSSL_malloc(msginlen + GROWTH_ALLOWANCE);
549 if (buf == NULL)
550 return 0;
551
552 fault->handbuf = buf;
553 fault->handbuflen = msginlen;
554 fault->handbufalloc = msginlen + GROWTH_ALLOWANCE;
555 memcpy(buf, msgin, msginlen);
556
557 if (!PACKET_buf_init(&pkt, buf, msginlen)
558 || !PACKET_get_1(&pkt, &msgtype)
559 || !PACKET_get_net_3(&pkt, &payloadlen)
560 || PACKET_remaining(&pkt) != payloadlen)
561 return 0;
562
563 /* Parse specific message types */
564 switch (msgtype) {
565 case SSL3_MT_ENCRYPTED_EXTENSIONS:
566 {
567 QTEST_ENCRYPTED_EXTENSIONS ee;
568
569 if (fault->encextcb == NULL)
570 break;
571
572 /*
573 * The EncryptedExtensions message is very simple. It just has an
574 * extensions block in it and nothing else.
575 */
576 ee.extensions = (unsigned char *)PACKET_data(&pkt);
577 ee.extensionslen = payloadlen;
578 if (!fault->encextcb(fault, &ee, payloadlen, fault->encextcbarg))
579 return 0;
580 }
581
582 default:
583 /* No specific handlers for these message types yet */
584 break;
585 }
586
587 if (fault->handshakecb != NULL
588 && !fault->handshakecb(fault, buf, fault->handbuflen,
589 fault->handshakecbarg))
590 return 0;
591
592 *msgout = buf;
593 *msgoutlen = fault->handbuflen;
594
595 return 1;
596 }
597
598 static void handshake_finish(void *arg)
599 {
600 QTEST_FAULT *fault = arg;
601
602 OPENSSL_free(fault->handbuf);
603 fault->handbuf = NULL;
604 }
605
606 int qtest_fault_set_handshake_listener(QTEST_FAULT *fault,
607 qtest_fault_on_handshake_cb handshakecb,
608 void *handshakecbarg)
609 {
610 fault->handshakecb = handshakecb;
611 fault->handshakecbarg = handshakecbarg;
612
613 return ossl_quic_tserver_set_handshake_mutator(fault->qtserv,
614 handshake_mutate,
615 handshake_finish,
616 fault);
617 }
618
619 int qtest_fault_set_hand_enc_ext_listener(QTEST_FAULT *fault,
620 qtest_fault_on_enc_ext_cb encextcb,
621 void *encextcbarg)
622 {
623 fault->encextcb = encextcb;
624 fault->encextcbarg = encextcbarg;
625
626 return ossl_quic_tserver_set_handshake_mutator(fault->qtserv,
627 handshake_mutate,
628 handshake_finish,
629 fault);
630 }
631
632 /* To be called from a handshake_listener callback */
633 int qtest_fault_resize_handshake(QTEST_FAULT *fault, size_t newlen)
634 {
635 unsigned char *buf;
636 size_t oldlen = fault->handbuflen;
637
638 /*
639 * Alloc'd size should always be non-zero, so if this fails we've been
640 * incorrectly called
641 */
642 if (fault->handbufalloc == 0)
643 return 0;
644
645 if (newlen > fault->handbufalloc) {
646 /* This exceeds our growth allowance. Fail */
647 return 0;
648 }
649
650 buf = (unsigned char *)fault->handbuf;
651
652 if (newlen > oldlen) {
653 /* Extend packet with 0 bytes */
654 memset(buf + oldlen, 0, newlen - oldlen);
655 } /* else we're truncating or staying the same */
656
657 fault->handbuflen = newlen;
658 return 1;
659 }
660
661 /* To be called from message specific listener callbacks */
662 int qtest_fault_resize_message(QTEST_FAULT *fault, size_t newlen)
663 {
664 /* First resize the underlying message */
665 if (!qtest_fault_resize_handshake(fault, newlen + SSL3_HM_HEADER_LENGTH))
666 return 0;
667
668 /* Fixup the handshake message header */
669 fault->handbuf[1] = (unsigned char)((newlen >> 16) & 0xff);
670 fault->handbuf[2] = (unsigned char)((newlen >> 8) & 0xff);
671 fault->handbuf[3] = (unsigned char)((newlen ) & 0xff);
672
673 return 1;
674 }
675
676 int qtest_fault_delete_extension(QTEST_FAULT *fault,
677 unsigned int exttype, unsigned char *ext,
678 size_t *extlen)
679 {
680 PACKET pkt, sub, subext;
681 unsigned int type;
682 const unsigned char *start, *end;
683 size_t newlen;
684 size_t msglen = fault->handbuflen;
685
686 if (!PACKET_buf_init(&pkt, ext, *extlen))
687 return 0;
688
689 /* Extension block starts with 2 bytes for extension block length */
690 if (!PACKET_as_length_prefixed_2(&pkt, &sub))
691 return 0;
692
693 do {
694 start = PACKET_data(&sub);
695 if (!PACKET_get_net_2(&sub, &type)
696 || !PACKET_get_length_prefixed_2(&sub, &subext))
697 return 0;
698 } while (type != exttype);
699
700 /* Found it */
701 end = PACKET_data(&sub);
702
703 /*
704 * If we're not the last extension we need to move the rest earlier. The
705 * cast below is safe because we own the underlying buffer and we're no
706 * longer making PACKET calls.
707 */
708 if (end < ext + *extlen)
709 memmove((unsigned char *)start, end, end - start);
710
711 /*
712 * Calculate new extensions payload length =
713 * Original length
714 * - 2 extension block length bytes
715 * - length of removed extension
716 */
717 newlen = *extlen - 2 - (end - start);
718
719 /* Fixup the length bytes for the extension block */
720 ext[0] = (unsigned char)((newlen >> 8) & 0xff);
721 ext[1] = (unsigned char)((newlen ) & 0xff);
722
723 /*
724 * Length of the whole extension block is the new payload length plus the
725 * 2 bytes for the length
726 */
727 *extlen = newlen + 2;
728
729 /* We can now resize the message */
730 if ((size_t)(end - start) + SSL3_HM_HEADER_LENGTH > msglen)
731 return 0; /* Should not happen */
732 msglen -= (end - start) + SSL3_HM_HEADER_LENGTH;
733 if (!qtest_fault_resize_message(fault, msglen))
734 return 0;
735
736 return 1;
737 }
738
739 #define BIO_TYPE_CIPHER_PACKET_FILTER (0x80 | BIO_TYPE_FILTER)
740
741 static BIO_METHOD *pcipherbiometh = NULL;
742
743 # define BIO_MSG_N(array, stride, n) (*(BIO_MSG *)((char *)(array) + (n)*(stride)))
744
745 static int pcipher_sendmmsg(BIO *b, BIO_MSG *msg, size_t stride,
746 size_t num_msg, uint64_t flags,
747 size_t *num_processed)
748 {
749 QTEST_FAULT *fault;
750 BIO *next = BIO_next(b);
751 ossl_ssize_t ret = 0;
752 size_t i = 0, tmpnump;
753 QUIC_PKT_HDR hdr;
754 PACKET pkt;
755 unsigned char *tmpdata;
756
757 if (next == NULL)
758 return 0;
759
760 fault = BIO_get_data(b);
761 if (fault == NULL
762 || (fault->pciphercb == NULL && fault->datagramcb == NULL))
763 return BIO_sendmmsg(next, msg, stride, num_msg, flags, num_processed);
764
765 if (num_msg == 0) {
766 *num_processed = 0;
767 return 1;
768 }
769
770 for (i = 0; i < num_msg; ++i) {
771 fault->msg = BIO_MSG_N(msg, stride, i);
772
773 /* Take a copy of the data so that callbacks can modify it */
774 tmpdata = OPENSSL_malloc(fault->msg.data_len + GROWTH_ALLOWANCE);
775 if (tmpdata == NULL)
776 return 0;
777 memcpy(tmpdata, fault->msg.data, fault->msg.data_len);
778 fault->msg.data = tmpdata;
779 fault->msgalloc = fault->msg.data_len + GROWTH_ALLOWANCE;
780
781 if (fault->pciphercb != NULL) {
782 if (!PACKET_buf_init(&pkt, fault->msg.data, fault->msg.data_len))
783 return 0;
784
785 do {
786 if (!ossl_quic_wire_decode_pkt_hdr(&pkt,
787 0 /* TODO(QUIC): Not sure how this should be set*/, 1,
788 0, &hdr, NULL))
789 goto out;
790
791 /*
792 * hdr.data is const - but its our buffer so casting away the
793 * const is safe
794 */
795 if (!fault->pciphercb(fault, &hdr, (unsigned char *)hdr.data,
796 hdr.len, fault->pciphercbarg))
797 goto out;
798
799 /*
800 * TODO(QUIC): At the moment modifications to hdr by the callback
801 * are ignored. We might need to rewrite the QUIC header to
802 * enable tests to change this. We also don't yet have a
803 * mechanism for the callback to change the encrypted data
804 * length. It's not clear if that's needed or not.
805 */
806 } while (PACKET_remaining(&pkt) > 0);
807 }
808
809 if (fault->datagramcb != NULL
810 && !fault->datagramcb(fault, &fault->msg, stride,
811 fault->datagramcbarg))
812 goto out;
813
814 if (!BIO_sendmmsg(next, &fault->msg, stride, 1, flags, &tmpnump)) {
815 *num_processed = i;
816 goto out;
817 }
818
819 OPENSSL_free(fault->msg.data);
820 fault->msg.data = NULL;
821 fault->msgalloc = 0;
822 }
823
824 *num_processed = i;
825 out:
826 ret = i > 0;
827 OPENSSL_free(fault->msg.data);
828 fault->msg.data = NULL;
829 return ret;
830 }
831
832 static long pcipher_ctrl(BIO *b, int cmd, long larg, void *parg)
833 {
834 BIO *next = BIO_next(b);
835
836 if (next == NULL)
837 return -1;
838
839 return BIO_ctrl(next, cmd, larg, parg);
840 }
841
842 BIO_METHOD *qtest_get_bio_method(void)
843 {
844 BIO_METHOD *tmp;
845
846 if (pcipherbiometh != NULL)
847 return pcipherbiometh;
848
849 tmp = BIO_meth_new(BIO_TYPE_CIPHER_PACKET_FILTER, "Cipher Packet Filter");
850
851 if (!TEST_ptr(tmp))
852 return NULL;
853
854 if (!TEST_true(BIO_meth_set_sendmmsg(tmp, pcipher_sendmmsg))
855 || !TEST_true(BIO_meth_set_ctrl(tmp, pcipher_ctrl)))
856 goto err;
857
858 pcipherbiometh = tmp;
859 tmp = NULL;
860 err:
861 BIO_meth_free(tmp);
862 return pcipherbiometh;
863 }
864
865 int qtest_fault_set_packet_cipher_listener(QTEST_FAULT *fault,
866 qtest_fault_on_packet_cipher_cb pciphercb,
867 void *pciphercbarg)
868 {
869 fault->pciphercb = pciphercb;
870 fault->pciphercbarg = pciphercbarg;
871
872 return 1;
873 }
874
875 int qtest_fault_set_datagram_listener(QTEST_FAULT *fault,
876 qtest_fault_on_datagram_cb datagramcb,
877 void *datagramcbarg)
878 {
879 fault->datagramcb = datagramcb;
880 fault->datagramcbarg = datagramcbarg;
881
882 return 1;
883 }
884
885 /* To be called from a datagram_listener callback */
886 int qtest_fault_resize_datagram(QTEST_FAULT *fault, size_t newlen)
887 {
888 if (newlen > fault->msgalloc)
889 return 0;
890
891 if (newlen > fault->msg.data_len)
892 memset((unsigned char *)fault->msg.data + fault->msg.data_len, 0,
893 newlen - fault->msg.data_len);
894
895 fault->msg.data_len = newlen;
896
897 return 1;
898 }