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