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