]> git.ipfire.org Git - thirdparty/openssl.git/blob - test/helpers/quictestlib.c
Add the capability to listen for datagrams
[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/bio.h>
12 #include "quictestlib.h"
13 #include "../testutil.h"
14 #include "internal/quic_wire_pkt.h"
15 #include "internal/quic_record_tx.h"
16 #include "internal/quic_error.h"
17 #include "internal/packet.h"
18
19 #define GROWTH_ALLOWANCE 1024
20
21 struct ossl_quic_fault {
22 QUIC_TSERVER *qtserv;
23
24 /* Plain packet mutations */
25 /* Header for the plaintext packet */
26 QUIC_PKT_HDR pplainhdr;
27 /* iovec for the plaintext packet data buffer */
28 OSSL_QTX_IOVEC pplainio;
29 /* Allocted size of the plaintext packet data buffer */
30 size_t pplainbuf_alloc;
31 ossl_quic_fault_on_packet_plain_cb pplaincb;
32 void *pplaincbarg;
33
34 /* Handshake message mutations */
35 /* Handshake message buffer */
36 unsigned char *handbuf;
37 /* Allocated size of the handshake message buffer */
38 size_t handbufalloc;
39 /* Actual length of the handshake message */
40 size_t handbuflen;
41 ossl_quic_fault_on_handshake_cb handshakecb;
42 void *handshakecbarg;
43 ossl_quic_fault_on_enc_ext_cb encextcb;
44 void *encextcbarg;
45
46 /* Cipher packet mutations */
47 ossl_quic_fault_on_packet_cipher_cb pciphercb;
48 void *pciphercbarg;
49
50 /* Datagram mutations */
51 ossl_quic_fault_on_datagram_cb datagramcb;
52 void *datagramcbarg;
53 /* The currently processed message */
54 BIO_MSG msg;
55 /* Allocated size of msg data buffer */
56 size_t msgalloc;
57 };
58
59 static void packet_plain_finish(void *arg);
60 static void handshake_finish(void *arg);
61
62 static BIO_METHOD *get_bio_method(void);
63
64 int qtest_create_quic_objects(SSL_CTX *clientctx, char *certfile, char *keyfile,
65 QUIC_TSERVER **qtserv, SSL **cssl,
66 OSSL_QUIC_FAULT **fault)
67 {
68 /* ALPN value as recognised by QUIC_TSERVER */
69 unsigned char alpn[] = { 8, 'o', 's', 's', 'l', 't', 'e', 's', 't' };
70 QUIC_TSERVER_ARGS tserver_args = {0};
71 BIO *cbio = NULL, *sbio = NULL, *fisbio = NULL;
72 BIO_ADDR *peeraddr = NULL;
73 struct in_addr ina = {0};
74
75 *qtserv = NULL;
76 if (fault != NULL)
77 *fault = NULL;
78 *cssl = SSL_new(clientctx);
79 if (!TEST_ptr(*cssl))
80 return 0;
81
82 if (!TEST_true(SSL_set_blocking_mode(*cssl, 0)))
83 goto err;
84
85 /* SSL_set_alpn_protos returns 0 for success! */
86 if (!TEST_false(SSL_set_alpn_protos(*cssl, alpn, sizeof(alpn))))
87 goto err;
88
89 if (!TEST_true(BIO_new_bio_dgram_pair(&cbio, 0, &sbio, 0)))
90 goto err;
91
92 if (!TEST_true(BIO_dgram_set_caps(cbio, BIO_DGRAM_CAP_HANDLES_DST_ADDR))
93 || !TEST_true(BIO_dgram_set_caps(sbio, BIO_DGRAM_CAP_HANDLES_DST_ADDR)))
94 goto err;
95
96 SSL_set_bio(*cssl, cbio, cbio);
97
98 if (!TEST_ptr(peeraddr = BIO_ADDR_new()))
99 goto err;
100
101 /* Dummy server address */
102 if (!TEST_true(BIO_ADDR_rawmake(peeraddr, AF_INET, &ina, sizeof(ina),
103 htons(0))))
104 goto err;
105
106 if (!TEST_true(SSL_set_initial_peer_addr(*cssl, peeraddr)))
107 goto err;
108
109 if (fault != NULL) {
110 *fault = OPENSSL_zalloc(sizeof(**fault));
111 if (*fault == NULL)
112 goto err;
113 }
114
115 fisbio = BIO_new(get_bio_method());
116 if (!TEST_ptr(fisbio))
117 goto err;
118
119 BIO_set_data(fisbio, fault == NULL ? NULL : *fault);
120
121 if (!TEST_ptr(BIO_push(fisbio, sbio)))
122 goto err;
123
124 tserver_args.net_rbio = sbio;
125 tserver_args.net_wbio = fisbio;
126
127 if (!TEST_ptr(*qtserv = ossl_quic_tserver_new(&tserver_args, certfile,
128 keyfile)))
129 goto err;
130
131 /* Ownership of fisbio and sbio is now held by *qtserv */
132 sbio = NULL;
133 fisbio = NULL;
134
135 if (fault != NULL)
136 (*fault)->qtserv = *qtserv;
137
138 BIO_ADDR_free(peeraddr);
139
140 return 1;
141 err:
142 BIO_ADDR_free(peeraddr);
143 BIO_free(cbio);
144 BIO_free(fisbio);
145 BIO_free(sbio);
146 SSL_free(*cssl);
147 ossl_quic_tserver_free(*qtserv);
148 if (fault != NULL)
149 OPENSSL_free(*fault);
150
151 return 0;
152 }
153
154 #define MAXLOOPS 1000
155
156 int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl)
157 {
158 int retc = -1, rets = 0, err, abortctr = 0, ret = 0;
159 int clienterr = 0, servererr = 0;
160
161 do {
162 err = SSL_ERROR_WANT_WRITE;
163 while (!clienterr && retc <= 0 && err == SSL_ERROR_WANT_WRITE) {
164 retc = SSL_connect(clientssl);
165 if (retc <= 0)
166 err = SSL_get_error(clientssl, retc);
167 }
168
169 if (!clienterr && retc <= 0 && err != SSL_ERROR_WANT_READ) {
170 TEST_info("SSL_connect() failed %d, %d", retc, err);
171 TEST_openssl_errors();
172 clienterr = 1;
173 }
174
175 /*
176 * We're cheating. We don't take any notice of SSL_get_tick_timeout()
177 * and tick everytime around the loop anyway. This is inefficient. We
178 * can get away with it in test code because we control both ends of
179 * the communications and don't expect network delays. This shouldn't
180 * be done in a real application.
181 */
182 if (!clienterr && retc <= 0)
183 SSL_tick(clientssl);
184 if (!servererr && rets <= 0) {
185 ossl_quic_tserver_tick(qtserv);
186 servererr = ossl_quic_tserver_is_term_any(qtserv, NULL);
187 if (!servererr)
188 rets = ossl_quic_tserver_is_handshake_confirmed(qtserv);
189 }
190
191 if (clienterr && servererr)
192 goto err;
193
194 if (++abortctr == MAXLOOPS) {
195 TEST_info("No progress made");
196 goto err;
197 }
198 } while ((retc <= 0 && !clienterr) || (rets <= 0 && !servererr));
199
200 if (!clienterr && !servererr)
201 ret = 1;
202 err:
203 return ret;
204 }
205
206 int qtest_check_server_protocol_err(QUIC_TSERVER *qtserv)
207 {
208 QUIC_TERMINATE_CAUSE cause;
209
210 ossl_quic_tserver_tick(qtserv);
211
212 /*
213 * Check that the server has received the protocol violation error
214 * connection close from the client
215 */
216 if (!TEST_true(ossl_quic_tserver_is_term_any(qtserv, &cause))
217 || !TEST_true(cause.remote)
218 || !TEST_uint64_t_eq(cause.error_code, QUIC_ERR_PROTOCOL_VIOLATION))
219 return 0;
220
221 return 1;
222 }
223
224 void ossl_quic_fault_free(OSSL_QUIC_FAULT *fault)
225 {
226 if (fault == NULL)
227 return;
228
229 packet_plain_finish(fault);
230 handshake_finish(fault);
231
232 OPENSSL_free(fault);
233 }
234
235 static int packet_plain_mutate(const QUIC_PKT_HDR *hdrin,
236 const OSSL_QTX_IOVEC *iovecin, size_t numin,
237 QUIC_PKT_HDR **hdrout,
238 const OSSL_QTX_IOVEC **iovecout,
239 size_t *numout,
240 void *arg)
241 {
242 OSSL_QUIC_FAULT *fault = arg;
243 size_t i, bufsz = 0;
244 unsigned char *cur;
245
246 /* Coalesce our data into a single buffer */
247
248 /* First calculate required buffer size */
249 for (i = 0; i < numin; i++)
250 bufsz += iovecin[i].buf_len;
251
252 fault->pplainio.buf_len = bufsz;
253
254 /* Add an allowance for possible growth */
255 bufsz += GROWTH_ALLOWANCE;
256
257 fault->pplainio.buf = cur = OPENSSL_malloc(bufsz);
258 if (cur == NULL) {
259 fault->pplainio.buf_len = 0;
260 return 0;
261 }
262
263 fault->pplainbuf_alloc = bufsz;
264
265 /* Copy in the data from the input buffers */
266 for (i = 0; i < numin; i++) {
267 memcpy(cur, iovecin[i].buf, iovecin[i].buf_len);
268 cur += iovecin[i].buf_len;
269 }
270
271 fault->pplainhdr = *hdrin;
272
273 /* Cast below is safe because we allocated the buffer */
274 if (fault->pplaincb != NULL
275 && !fault->pplaincb(fault, &fault->pplainhdr,
276 (unsigned char *)fault->pplainio.buf,
277 fault->pplainio.buf_len, fault->pplaincbarg))
278 return 0;
279
280 *hdrout = &fault->pplainhdr;
281 *iovecout = &fault->pplainio;
282 *numout = 1;
283
284 return 1;
285 }
286
287 static void packet_plain_finish(void *arg)
288 {
289 OSSL_QUIC_FAULT *fault = arg;
290
291 /* Cast below is safe because we allocated the buffer */
292 OPENSSL_free((unsigned char *)fault->pplainio.buf);
293 fault->pplainio.buf_len = 0;
294 fault->pplainbuf_alloc = 0;
295 fault->pplainio.buf = NULL;
296 }
297
298 int ossl_quic_fault_set_packet_plain_listener(OSSL_QUIC_FAULT *fault,
299 ossl_quic_fault_on_packet_plain_cb pplaincb,
300 void *pplaincbarg)
301 {
302 fault->pplaincb = pplaincb;
303 fault->pplaincbarg = pplaincbarg;
304
305 return ossl_quic_tserver_set_plain_packet_mutator(fault->qtserv,
306 packet_plain_mutate,
307 packet_plain_finish,
308 fault);
309 }
310
311 /* To be called from a packet_plain_listener callback */
312 int ossl_quic_fault_resize_plain_packet(OSSL_QUIC_FAULT *fault, size_t newlen)
313 {
314 unsigned char *buf;
315 size_t oldlen = fault->pplainio.buf_len;
316
317 /*
318 * Alloc'd size should always be non-zero, so if this fails we've been
319 * incorrectly called
320 */
321 if (fault->pplainbuf_alloc == 0)
322 return 0;
323
324 if (newlen > fault->pplainbuf_alloc) {
325 /* This exceeds our growth allowance. Fail */
326 return 0;
327 }
328
329 /* Cast below is safe because we allocated the buffer */
330 buf = (unsigned char *)fault->pplainio.buf;
331
332 if (newlen > oldlen) {
333 /* Extend packet with 0 bytes */
334 memset(buf + oldlen, 0, newlen - oldlen);
335 } /* else we're truncating or staying the same */
336
337 fault->pplainio.buf_len = newlen;
338 fault->pplainhdr.len = newlen;
339
340 return 1;
341 }
342
343 static int handshake_mutate(const unsigned char *msgin, size_t msginlen,
344 unsigned char **msgout, size_t *msgoutlen,
345 void *arg)
346 {
347 OSSL_QUIC_FAULT *fault = arg;
348 unsigned char *buf;
349 unsigned long payloadlen;
350 unsigned int msgtype;
351 PACKET pkt;
352
353 buf = OPENSSL_malloc(msginlen + GROWTH_ALLOWANCE);
354 if (buf == NULL)
355 return 0;
356
357 fault->handbuf = buf;
358 fault->handbuflen = msginlen;
359 fault->handbufalloc = msginlen + GROWTH_ALLOWANCE;
360 memcpy(buf, msgin, msginlen);
361
362 if (!PACKET_buf_init(&pkt, buf, msginlen)
363 || !PACKET_get_1(&pkt, &msgtype)
364 || !PACKET_get_net_3(&pkt, &payloadlen)
365 || PACKET_remaining(&pkt) != payloadlen)
366 return 0;
367
368 /* Parse specific message types */
369 switch (msgtype) {
370 case SSL3_MT_ENCRYPTED_EXTENSIONS:
371 {
372 OSSL_QF_ENCRYPTED_EXTENSIONS ee;
373
374 if (fault->encextcb == NULL)
375 break;
376
377 /*
378 * The EncryptedExtensions message is very simple. It just has an
379 * extensions block in it and nothing else.
380 */
381 ee.extensions = (unsigned char *)PACKET_data(&pkt);
382 ee.extensionslen = payloadlen;
383 if (!fault->encextcb(fault, &ee, payloadlen, fault->encextcbarg))
384 return 0;
385 }
386
387 default:
388 /* No specific handlers for these message types yet */
389 break;
390 }
391
392 if (fault->handshakecb != NULL
393 && !fault->handshakecb(fault, buf, fault->handbuflen,
394 fault->handshakecbarg))
395 return 0;
396
397 *msgout = buf;
398 *msgoutlen = fault->handbuflen;
399
400 return 1;
401 }
402
403 static void handshake_finish(void *arg)
404 {
405 OSSL_QUIC_FAULT *fault = arg;
406
407 OPENSSL_free(fault->handbuf);
408 fault->handbuf = NULL;
409 }
410
411 int ossl_quic_fault_set_handshake_listener(OSSL_QUIC_FAULT *fault,
412 ossl_quic_fault_on_handshake_cb handshakecb,
413 void *handshakecbarg)
414 {
415 fault->handshakecb = handshakecb;
416 fault->handshakecbarg = handshakecbarg;
417
418 return ossl_quic_tserver_set_handshake_mutator(fault->qtserv,
419 handshake_mutate,
420 handshake_finish,
421 fault);
422 }
423
424 int ossl_quic_fault_set_hand_enc_ext_listener(OSSL_QUIC_FAULT *fault,
425 ossl_quic_fault_on_enc_ext_cb encextcb,
426 void *encextcbarg)
427 {
428 fault->encextcb = encextcb;
429 fault->encextcbarg = encextcbarg;
430
431 return ossl_quic_tserver_set_handshake_mutator(fault->qtserv,
432 handshake_mutate,
433 handshake_finish,
434 fault);
435 }
436
437 /* To be called from a handshake_listener callback */
438 int ossl_quic_fault_resize_handshake(OSSL_QUIC_FAULT *fault, size_t newlen)
439 {
440 unsigned char *buf;
441 size_t oldlen = fault->handbuflen;
442
443 /*
444 * Alloc'd size should always be non-zero, so if this fails we've been
445 * incorrectly called
446 */
447 if (fault->handbufalloc == 0)
448 return 0;
449
450 if (newlen > fault->handbufalloc) {
451 /* This exceeds our growth allowance. Fail */
452 return 0;
453 }
454
455 buf = (unsigned char *)fault->handbuf;
456
457 if (newlen > oldlen) {
458 /* Extend packet with 0 bytes */
459 memset(buf + oldlen, 0, newlen - oldlen);
460 } /* else we're truncating or staying the same */
461
462 fault->handbuflen = newlen;
463 return 1;
464 }
465
466 /* To be called from message specific listener callbacks */
467 int ossl_quic_fault_resize_message(OSSL_QUIC_FAULT *fault, size_t newlen)
468 {
469 /* First resize the underlying message */
470 if (!ossl_quic_fault_resize_handshake(fault, newlen + SSL3_HM_HEADER_LENGTH))
471 return 0;
472
473 /* Fixup the handshake message header */
474 fault->handbuf[1] = (unsigned char)((newlen >> 16) & 0xff);
475 fault->handbuf[2] = (unsigned char)((newlen >> 8) & 0xff);
476 fault->handbuf[3] = (unsigned char)((newlen ) & 0xff);
477
478 return 1;
479 }
480
481 int ossl_quic_fault_delete_extension(OSSL_QUIC_FAULT *fault,
482 unsigned int exttype, unsigned char *ext,
483 size_t *extlen)
484 {
485 PACKET pkt, sub, subext;
486 unsigned int type;
487 const unsigned char *start, *end;
488 size_t newlen;
489 size_t msglen = fault->handbuflen;
490
491 if (!PACKET_buf_init(&pkt, ext, *extlen))
492 return 0;
493
494 /* Extension block starts with 2 bytes for extension block length */
495 if (!PACKET_as_length_prefixed_2(&pkt, &sub))
496 return 0;
497
498 do {
499 start = PACKET_data(&sub);
500 if (!PACKET_get_net_2(&sub, &type)
501 || !PACKET_get_length_prefixed_2(&sub, &subext))
502 return 0;
503 } while (type != exttype);
504
505 /* Found it */
506 end = PACKET_data(&sub);
507
508 /*
509 * If we're not the last extension we need to move the rest earlier. The
510 * cast below is safe because we own the underlying buffer and we're no
511 * longer making PACKET calls.
512 */
513 if (end < ext + *extlen)
514 memmove((unsigned char *)start, end, end - start);
515
516 /*
517 * Calculate new extensions payload length =
518 * Original length
519 * - 2 extension block length bytes
520 * - length of removed extension
521 */
522 newlen = *extlen - 2 - (end - start);
523
524 /* Fixup the length bytes for the extension block */
525 ext[0] = (unsigned char)((newlen >> 8) & 0xff);
526 ext[1] = (unsigned char)((newlen ) & 0xff);
527
528 /*
529 * Length of the whole extension block is the new payload length plus the
530 * 2 bytes for the length
531 */
532 *extlen = newlen + 2;
533
534 /* We can now resize the message */
535 if ((size_t)(end - start) + SSL3_HM_HEADER_LENGTH > msglen)
536 return 0; /* Should not happen */
537 msglen -= (end - start) + SSL3_HM_HEADER_LENGTH;
538 if (!ossl_quic_fault_resize_message(fault, msglen))
539 return 0;
540
541 return 1;
542 }
543
544 #define BIO_TYPE_CIPHER_PACKET_FILTER (0x80 | BIO_TYPE_FILTER)
545
546 static BIO_METHOD *pcipherbiometh = NULL;
547
548 # define BIO_MSG_N(array, stride, n) (*(BIO_MSG *)((char *)(array) + (n)*(stride)))
549
550 static int pcipher_sendmmsg(BIO *b, BIO_MSG *msg, size_t stride,
551 size_t num_msg, uint64_t flags,
552 size_t *num_processed)
553 {
554 OSSL_QUIC_FAULT *fault;
555 BIO *next = BIO_next(b);
556 ossl_ssize_t ret = 0;
557 size_t i = 0, tmpnump;
558 QUIC_PKT_HDR hdr;
559 PACKET pkt;
560 unsigned char *tmpdata;
561
562 if (next == NULL)
563 return 0;
564
565 fault = BIO_get_data(b);
566 if (fault == NULL
567 || (fault->pciphercb == NULL && fault->datagramcb == NULL))
568 return BIO_sendmmsg(next, msg, stride, num_msg, flags, num_processed);
569
570 if (num_msg == 0) {
571 *num_processed = 0;
572 return 1;
573 }
574
575 for (i = 0; i < num_msg; ++i) {
576 fault->msg = BIO_MSG_N(msg, stride, i);
577
578 /* Take a copy of the data so that callbacks can modify it */
579 tmpdata = OPENSSL_malloc(fault->msg.data_len + GROWTH_ALLOWANCE);
580 if (tmpdata == NULL)
581 return 0;
582 memcpy(tmpdata, fault->msg.data, fault->msg.data_len);
583 fault->msg.data = tmpdata;
584 fault->msgalloc = fault->msg.data_len + GROWTH_ALLOWANCE;
585
586 if (fault->pciphercb != NULL) {
587 if (!PACKET_buf_init(&pkt, fault->msg.data, fault->msg.data_len))
588 return 0;
589
590 do {
591 if (!ossl_quic_wire_decode_pkt_hdr(&pkt,
592 0 /* TODO(QUIC): Not sure how this should be set*/, 1,
593 &hdr, NULL))
594 goto out;
595
596 /*
597 * hdr.data is const - but its our buffer so casting away the
598 * const is safe
599 */
600 if (!fault->pciphercb(fault, &hdr, (unsigned char *)hdr.data,
601 hdr.len, fault->pciphercbarg))
602 goto out;
603
604 /*
605 * TODO(QUIC): At the moment modifications to hdr by the callback
606 * are ignored. We might need to rewrite the QUIC header to
607 * enable tests to change this. We also don't yet have a
608 * mechanism for the callback to change the encrypted data
609 * length. It's not clear if that's needed or not.
610 */
611 } while (PACKET_remaining(&pkt) > 0);
612 }
613
614 if (fault->datagramcb != NULL
615 && !fault->datagramcb(fault, &fault->msg, stride,
616 fault->datagramcbarg))
617 goto out;
618
619 if (!BIO_sendmmsg(next, &fault->msg, stride, 1, flags, &tmpnump)) {
620 *num_processed = i;
621 goto out;
622 }
623
624 OPENSSL_free(fault->msg.data);
625 fault->msg.data = NULL;
626 fault->msgalloc = 0;
627 }
628
629 *num_processed = i;
630 ret = 1;
631 out:
632 if (i > 0)
633 ret = 1;
634 else
635 ret = 0;
636 OPENSSL_free(fault->msg.data);
637 fault->msg.data = NULL;
638 return ret;
639 }
640
641 static long pcipher_ctrl(BIO *b, int cmd, long larg, void *parg)
642 {
643 BIO *next = BIO_next(b);
644
645 if (next == NULL)
646 return -1;
647
648 return BIO_ctrl(next, cmd, larg, parg);
649 }
650
651 static BIO_METHOD *get_bio_method(void)
652 {
653 BIO_METHOD *tmp;
654
655 if (pcipherbiometh != NULL)
656 return pcipherbiometh;
657
658 tmp = BIO_meth_new(BIO_TYPE_CIPHER_PACKET_FILTER, "Cipher Packet Filter");
659
660 if (!TEST_ptr(tmp))
661 return NULL;
662
663 if (!TEST_true(BIO_meth_set_sendmmsg(tmp, pcipher_sendmmsg))
664 || !TEST_true(BIO_meth_set_ctrl(tmp, pcipher_ctrl)))
665 goto err;
666
667 pcipherbiometh = tmp;
668 tmp = NULL;
669 err:
670 BIO_meth_free(tmp);
671 return pcipherbiometh;
672 }
673
674 int ossl_quic_fault_set_packet_cipher_listener(OSSL_QUIC_FAULT *fault,
675 ossl_quic_fault_on_packet_cipher_cb pciphercb,
676 void *pciphercbarg)
677 {
678 fault->pciphercb = pciphercb;
679 fault->pciphercbarg = pciphercbarg;
680
681 return 1;
682 }
683
684 int ossl_quic_fault_set_datagram_listener(OSSL_QUIC_FAULT *fault,
685 ossl_quic_fault_on_datagram_cb datagramcb,
686 void *datagramcbarg)
687 {
688 fault->datagramcb = datagramcb;
689 fault->datagramcbarg = datagramcbarg;
690
691 return 1;
692 }
693
694 /* To be called from a datagram_listener callback */
695 int ossl_quic_fault_resize_datagram(OSSL_QUIC_FAULT *fault, size_t newlen)
696 {
697 if (newlen > fault->msgalloc)
698 return 0;
699
700 if (newlen > fault->msg.data_len)
701 memset((unsigned char *)fault->msg.data + fault->msg.data_len, 0,
702 newlen - fault->msg.data_len);
703
704 fault->msg.data_len = newlen;
705
706 return 1;
707 }