2 * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
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
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"
19 #define GROWTH_ALLOWANCE 1024
21 struct ossl_quic_fault
{
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
;
34 /* Handshake message mutations */
35 /* Handshake message buffer */
36 unsigned char *handbuf
;
37 /* Allocated size of the handshake message buffer */
39 /* Actual length of the handshake message */
41 ossl_quic_fault_on_handshake_cb handshakecb
;
43 ossl_quic_fault_on_enc_ext_cb encextcb
;
46 /* Cipher packet mutations */
47 ossl_quic_fault_on_packet_cipher_cb pciphercb
;
50 /* Datagram mutations */
51 ossl_quic_fault_on_datagram_cb datagramcb
;
53 /* The currently processed message */
55 /* Allocated size of msg data buffer */
59 static void packet_plain_finish(void *arg
);
60 static void handshake_finish(void *arg
);
62 static BIO_METHOD
*get_bio_method(void);
64 int qtest_create_quic_objects(SSL_CTX
*clientctx
, char *certfile
, char *keyfile
,
65 QUIC_TSERVER
**qtserv
, SSL
**cssl
,
66 OSSL_QUIC_FAULT
**fault
)
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};
78 *cssl
= SSL_new(clientctx
);
82 if (!TEST_true(SSL_set_blocking_mode(*cssl
, 0)))
85 /* SSL_set_alpn_protos returns 0 for success! */
86 if (!TEST_false(SSL_set_alpn_protos(*cssl
, alpn
, sizeof(alpn
))))
89 if (!TEST_true(BIO_new_bio_dgram_pair(&cbio
, 0, &sbio
, 0)))
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
)))
96 SSL_set_bio(*cssl
, cbio
, cbio
);
98 if (!TEST_ptr(peeraddr
= BIO_ADDR_new()))
101 /* Dummy server address */
102 if (!TEST_true(BIO_ADDR_rawmake(peeraddr
, AF_INET
, &ina
, sizeof(ina
),
106 if (!TEST_true(SSL_set_initial_peer_addr(*cssl
, peeraddr
)))
110 *fault
= OPENSSL_zalloc(sizeof(**fault
));
115 fisbio
= BIO_new(get_bio_method());
116 if (!TEST_ptr(fisbio
))
119 BIO_set_data(fisbio
, fault
== NULL
? NULL
: *fault
);
121 if (!TEST_ptr(BIO_push(fisbio
, sbio
)))
124 tserver_args
.net_rbio
= sbio
;
125 tserver_args
.net_wbio
= fisbio
;
127 if (!TEST_ptr(*qtserv
= ossl_quic_tserver_new(&tserver_args
, certfile
,
131 /* Ownership of fisbio and sbio is now held by *qtserv */
136 (*fault
)->qtserv
= *qtserv
;
138 BIO_ADDR_free(peeraddr
);
142 BIO_ADDR_free(peeraddr
);
147 ossl_quic_tserver_free(*qtserv
);
149 OPENSSL_free(*fault
);
154 #define MAXLOOPS 1000
156 int qtest_create_quic_connection(QUIC_TSERVER
*qtserv
, SSL
*clientssl
)
158 int retc
= -1, rets
= 0, err
, abortctr
= 0, ret
= 0;
159 int clienterr
= 0, servererr
= 0;
162 err
= SSL_ERROR_WANT_WRITE
;
163 while (!clienterr
&& retc
<= 0 && err
== SSL_ERROR_WANT_WRITE
) {
164 retc
= SSL_connect(clientssl
);
166 err
= SSL_get_error(clientssl
, retc
);
169 if (!clienterr
&& retc
<= 0 && err
!= SSL_ERROR_WANT_READ
) {
170 TEST_info("SSL_connect() failed %d, %d", retc
, err
);
171 TEST_openssl_errors();
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.
182 if (!clienterr
&& retc
<= 0)
184 if (!servererr
&& rets
<= 0) {
185 ossl_quic_tserver_tick(qtserv
);
186 servererr
= ossl_quic_tserver_is_term_any(qtserv
, NULL
);
188 rets
= ossl_quic_tserver_is_handshake_confirmed(qtserv
);
191 if (clienterr
&& servererr
)
194 if (++abortctr
== MAXLOOPS
) {
195 TEST_info("No progress made");
198 } while ((retc
<= 0 && !clienterr
) || (rets
<= 0 && !servererr
));
200 if (!clienterr
&& !servererr
)
206 int qtest_check_server_protocol_err(QUIC_TSERVER
*qtserv
)
208 QUIC_TERMINATE_CAUSE cause
;
210 ossl_quic_tserver_tick(qtserv
);
213 * Check that the server has received the protocol violation error
214 * connection close from the client
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
))
224 void ossl_quic_fault_free(OSSL_QUIC_FAULT
*fault
)
229 packet_plain_finish(fault
);
230 handshake_finish(fault
);
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
,
242 OSSL_QUIC_FAULT
*fault
= arg
;
246 /* Coalesce our data into a single buffer */
248 /* First calculate required buffer size */
249 for (i
= 0; i
< numin
; i
++)
250 bufsz
+= iovecin
[i
].buf_len
;
252 fault
->pplainio
.buf_len
= bufsz
;
254 /* Add an allowance for possible growth */
255 bufsz
+= GROWTH_ALLOWANCE
;
257 fault
->pplainio
.buf
= cur
= OPENSSL_malloc(bufsz
);
259 fault
->pplainio
.buf_len
= 0;
263 fault
->pplainbuf_alloc
= bufsz
;
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
;
271 fault
->pplainhdr
= *hdrin
;
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
))
280 *hdrout
= &fault
->pplainhdr
;
281 *iovecout
= &fault
->pplainio
;
287 static void packet_plain_finish(void *arg
)
289 OSSL_QUIC_FAULT
*fault
= arg
;
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
;
298 int ossl_quic_fault_set_packet_plain_listener(OSSL_QUIC_FAULT
*fault
,
299 ossl_quic_fault_on_packet_plain_cb pplaincb
,
302 fault
->pplaincb
= pplaincb
;
303 fault
->pplaincbarg
= pplaincbarg
;
305 return ossl_quic_tserver_set_plain_packet_mutator(fault
->qtserv
,
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
)
315 size_t oldlen
= fault
->pplainio
.buf_len
;
318 * Alloc'd size should always be non-zero, so if this fails we've been
321 if (fault
->pplainbuf_alloc
== 0)
324 if (newlen
> fault
->pplainbuf_alloc
) {
325 /* This exceeds our growth allowance. Fail */
329 /* Cast below is safe because we allocated the buffer */
330 buf
= (unsigned char *)fault
->pplainio
.buf
;
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 */
337 fault
->pplainio
.buf_len
= newlen
;
338 fault
->pplainhdr
.len
= newlen
;
343 static int handshake_mutate(const unsigned char *msgin
, size_t msginlen
,
344 unsigned char **msgout
, size_t *msgoutlen
,
347 OSSL_QUIC_FAULT
*fault
= arg
;
349 unsigned long payloadlen
;
350 unsigned int msgtype
;
353 buf
= OPENSSL_malloc(msginlen
+ GROWTH_ALLOWANCE
);
357 fault
->handbuf
= buf
;
358 fault
->handbuflen
= msginlen
;
359 fault
->handbufalloc
= msginlen
+ GROWTH_ALLOWANCE
;
360 memcpy(buf
, msgin
, msginlen
);
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
)
368 /* Parse specific message types */
370 case SSL3_MT_ENCRYPTED_EXTENSIONS
:
372 OSSL_QF_ENCRYPTED_EXTENSIONS ee
;
374 if (fault
->encextcb
== NULL
)
378 * The EncryptedExtensions message is very simple. It just has an
379 * extensions block in it and nothing else.
381 ee
.extensions
= (unsigned char *)PACKET_data(&pkt
);
382 ee
.extensionslen
= payloadlen
;
383 if (!fault
->encextcb(fault
, &ee
, payloadlen
, fault
->encextcbarg
))
388 /* No specific handlers for these message types yet */
392 if (fault
->handshakecb
!= NULL
393 && !fault
->handshakecb(fault
, buf
, fault
->handbuflen
,
394 fault
->handshakecbarg
))
398 *msgoutlen
= fault
->handbuflen
;
403 static void handshake_finish(void *arg
)
405 OSSL_QUIC_FAULT
*fault
= arg
;
407 OPENSSL_free(fault
->handbuf
);
408 fault
->handbuf
= NULL
;
411 int ossl_quic_fault_set_handshake_listener(OSSL_QUIC_FAULT
*fault
,
412 ossl_quic_fault_on_handshake_cb handshakecb
,
413 void *handshakecbarg
)
415 fault
->handshakecb
= handshakecb
;
416 fault
->handshakecbarg
= handshakecbarg
;
418 return ossl_quic_tserver_set_handshake_mutator(fault
->qtserv
,
424 int ossl_quic_fault_set_hand_enc_ext_listener(OSSL_QUIC_FAULT
*fault
,
425 ossl_quic_fault_on_enc_ext_cb encextcb
,
428 fault
->encextcb
= encextcb
;
429 fault
->encextcbarg
= encextcbarg
;
431 return ossl_quic_tserver_set_handshake_mutator(fault
->qtserv
,
437 /* To be called from a handshake_listener callback */
438 int ossl_quic_fault_resize_handshake(OSSL_QUIC_FAULT
*fault
, size_t newlen
)
441 size_t oldlen
= fault
->handbuflen
;
444 * Alloc'd size should always be non-zero, so if this fails we've been
447 if (fault
->handbufalloc
== 0)
450 if (newlen
> fault
->handbufalloc
) {
451 /* This exceeds our growth allowance. Fail */
455 buf
= (unsigned char *)fault
->handbuf
;
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 */
462 fault
->handbuflen
= newlen
;
466 /* To be called from message specific listener callbacks */
467 int ossl_quic_fault_resize_message(OSSL_QUIC_FAULT
*fault
, size_t newlen
)
469 /* First resize the underlying message */
470 if (!ossl_quic_fault_resize_handshake(fault
, newlen
+ SSL3_HM_HEADER_LENGTH
))
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);
481 int ossl_quic_fault_delete_extension(OSSL_QUIC_FAULT
*fault
,
482 unsigned int exttype
, unsigned char *ext
,
485 PACKET pkt
, sub
, subext
;
487 const unsigned char *start
, *end
;
489 size_t msglen
= fault
->handbuflen
;
491 if (!PACKET_buf_init(&pkt
, ext
, *extlen
))
494 /* Extension block starts with 2 bytes for extension block length */
495 if (!PACKET_as_length_prefixed_2(&pkt
, &sub
))
499 start
= PACKET_data(&sub
);
500 if (!PACKET_get_net_2(&sub
, &type
)
501 || !PACKET_get_length_prefixed_2(&sub
, &subext
))
503 } while (type
!= exttype
);
506 end
= PACKET_data(&sub
);
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.
513 if (end
< ext
+ *extlen
)
514 memmove((unsigned char *)start
, end
, end
- start
);
517 * Calculate new extensions payload length =
519 * - 2 extension block length bytes
520 * - length of removed extension
522 newlen
= *extlen
- 2 - (end
- start
);
524 /* Fixup the length bytes for the extension block */
525 ext
[0] = (unsigned char)((newlen
>> 8) & 0xff);
526 ext
[1] = (unsigned char)((newlen
) & 0xff);
529 * Length of the whole extension block is the new payload length plus the
530 * 2 bytes for the length
532 *extlen
= newlen
+ 2;
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
))
544 #define BIO_TYPE_CIPHER_PACKET_FILTER (0x80 | BIO_TYPE_FILTER)
546 static BIO_METHOD
*pcipherbiometh
= NULL
;
548 # define BIO_MSG_N(array, stride, n) (*(BIO_MSG *)((char *)(array) + (n)*(stride)))
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
)
554 OSSL_QUIC_FAULT
*fault
;
555 BIO
*next
= BIO_next(b
);
556 ossl_ssize_t ret
= 0;
557 size_t i
= 0, tmpnump
;
560 unsigned char *tmpdata
;
565 fault
= BIO_get_data(b
);
567 || (fault
->pciphercb
== NULL
&& fault
->datagramcb
== NULL
))
568 return BIO_sendmmsg(next
, msg
, stride
, num_msg
, flags
, num_processed
);
575 for (i
= 0; i
< num_msg
; ++i
) {
576 fault
->msg
= BIO_MSG_N(msg
, stride
, i
);
578 /* Take a copy of the data so that callbacks can modify it */
579 tmpdata
= OPENSSL_malloc(fault
->msg
.data_len
+ GROWTH_ALLOWANCE
);
582 memcpy(tmpdata
, fault
->msg
.data
, fault
->msg
.data_len
);
583 fault
->msg
.data
= tmpdata
;
584 fault
->msgalloc
= fault
->msg
.data_len
+ GROWTH_ALLOWANCE
;
586 if (fault
->pciphercb
!= NULL
) {
587 if (!PACKET_buf_init(&pkt
, fault
->msg
.data
, fault
->msg
.data_len
))
591 if (!ossl_quic_wire_decode_pkt_hdr(&pkt
,
592 0 /* TODO(QUIC): Not sure how this should be set*/, 1,
597 * hdr.data is const - but its our buffer so casting away the
600 if (!fault
->pciphercb(fault
, &hdr
, (unsigned char *)hdr
.data
,
601 hdr
.len
, fault
->pciphercbarg
))
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.
611 } while (PACKET_remaining(&pkt
) > 0);
614 if (fault
->datagramcb
!= NULL
615 && !fault
->datagramcb(fault
, &fault
->msg
, stride
,
616 fault
->datagramcbarg
))
619 if (!BIO_sendmmsg(next
, &fault
->msg
, stride
, 1, flags
, &tmpnump
)) {
624 OPENSSL_free(fault
->msg
.data
);
625 fault
->msg
.data
= NULL
;
636 OPENSSL_free(fault
->msg
.data
);
637 fault
->msg
.data
= NULL
;
641 static long pcipher_ctrl(BIO
*b
, int cmd
, long larg
, void *parg
)
643 BIO
*next
= BIO_next(b
);
648 return BIO_ctrl(next
, cmd
, larg
, parg
);
651 static BIO_METHOD
*get_bio_method(void)
655 if (pcipherbiometh
!= NULL
)
656 return pcipherbiometh
;
658 tmp
= BIO_meth_new(BIO_TYPE_CIPHER_PACKET_FILTER
, "Cipher Packet Filter");
663 if (!TEST_true(BIO_meth_set_sendmmsg(tmp
, pcipher_sendmmsg
))
664 || !TEST_true(BIO_meth_set_ctrl(tmp
, pcipher_ctrl
)))
667 pcipherbiometh
= tmp
;
671 return pcipherbiometh
;
674 int ossl_quic_fault_set_packet_cipher_listener(OSSL_QUIC_FAULT
*fault
,
675 ossl_quic_fault_on_packet_cipher_cb pciphercb
,
678 fault
->pciphercb
= pciphercb
;
679 fault
->pciphercbarg
= pciphercbarg
;
684 int ossl_quic_fault_set_datagram_listener(OSSL_QUIC_FAULT
*fault
,
685 ossl_quic_fault_on_datagram_cb datagramcb
,
688 fault
->datagramcb
= datagramcb
;
689 fault
->datagramcbarg
= datagramcbarg
;
694 /* To be called from a datagram_listener callback */
695 int ossl_quic_fault_resize_datagram(OSSL_QUIC_FAULT
*fault
, size_t newlen
)
697 if (newlen
> fault
->msgalloc
)
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
);
704 fault
->msg
.data_len
= newlen
;