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