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
;
51 static void packet_plain_finish(void *arg
);
52 static void handshake_finish(void *arg
);
54 static BIO_METHOD
*get_bio_method(void);
56 int qtest_create_quic_objects(SSL_CTX
*clientctx
, char *certfile
, char *keyfile
,
57 QUIC_TSERVER
**qtserv
, SSL
**cssl
,
58 OSSL_QUIC_FAULT
**fault
)
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};
70 *cssl
= SSL_new(clientctx
);
74 if (!TEST_true(SSL_set_blocking_mode(*cssl
, 0)))
77 /* SSL_set_alpn_protos returns 0 for success! */
78 if (!TEST_false(SSL_set_alpn_protos(*cssl
, alpn
, sizeof(alpn
))))
81 if (!TEST_true(BIO_new_bio_dgram_pair(&cbio
, 0, &sbio
, 0)))
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
)))
88 SSL_set_bio(*cssl
, cbio
, cbio
);
90 if (!TEST_ptr(peeraddr
= BIO_ADDR_new()))
93 /* Dummy server address */
94 if (!TEST_true(BIO_ADDR_rawmake(peeraddr
, AF_INET
, &ina
, sizeof(ina
),
98 if (!TEST_true(SSL_set_initial_peer_addr(*cssl
, peeraddr
)))
102 *fault
= OPENSSL_zalloc(sizeof(**fault
));
107 fisbio
= BIO_new(get_bio_method());
108 if (!TEST_ptr(fisbio
))
111 BIO_set_data(fisbio
, fault
== NULL
? NULL
: *fault
);
113 if (!TEST_ptr(BIO_push(fisbio
, sbio
)))
116 tserver_args
.net_rbio
= sbio
;
117 tserver_args
.net_wbio
= fisbio
;
119 if (!TEST_ptr(*qtserv
= ossl_quic_tserver_new(&tserver_args
, certfile
,
123 /* Ownership of fisbio and sbio is now held by *qtserv */
128 (*fault
)->qtserv
= *qtserv
;
130 BIO_ADDR_free(peeraddr
);
134 BIO_ADDR_free(peeraddr
);
139 ossl_quic_tserver_free(*qtserv
);
141 OPENSSL_free(*fault
);
146 #define MAXLOOPS 1000
148 int qtest_create_quic_connection(QUIC_TSERVER
*qtserv
, SSL
*clientssl
)
150 int retc
= -1, rets
= 0, err
, abortctr
= 0, ret
= 0;
151 int clienterr
= 0, servererr
= 0;
154 err
= SSL_ERROR_WANT_WRITE
;
155 while (!clienterr
&& retc
<= 0 && err
== SSL_ERROR_WANT_WRITE
) {
156 retc
= SSL_connect(clientssl
);
158 err
= SSL_get_error(clientssl
, retc
);
161 if (!clienterr
&& retc
<= 0 && err
!= SSL_ERROR_WANT_READ
) {
162 TEST_info("SSL_connect() failed %d, %d", retc
, err
);
163 TEST_openssl_errors();
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.
174 if (!clienterr
&& retc
<= 0)
176 if (!servererr
&& rets
<= 0) {
177 ossl_quic_tserver_tick(qtserv
);
178 servererr
= ossl_quic_tserver_is_term_any(qtserv
, NULL
);
180 rets
= ossl_quic_tserver_is_handshake_complete(qtserv
);
183 if (clienterr
&& servererr
)
186 if (++abortctr
== MAXLOOPS
) {
187 TEST_info("No progress made");
190 } while ((retc
<= 0 && !clienterr
) || (rets
<= 0 && !servererr
));
192 if (!clienterr
&& !servererr
)
198 int qtest_check_server_protocol_err(QUIC_TSERVER
*qtserv
)
200 QUIC_TERMINATE_CAUSE cause
;
202 ossl_quic_tserver_tick(qtserv
);
205 * Check that the server has received the protocol violation error
206 * connection close from the client
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
))
216 void ossl_quic_fault_free(OSSL_QUIC_FAULT
*fault
)
221 packet_plain_finish(fault
);
222 handshake_finish(fault
);
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
,
234 OSSL_QUIC_FAULT
*fault
= arg
;
238 /* Coalesce our data into a single buffer */
240 /* First calculate required buffer size */
241 for (i
= 0; i
< numin
; i
++)
242 bufsz
+= iovecin
[i
].buf_len
;
244 fault
->pplainio
.buf_len
= bufsz
;
246 /* Add an allowance for possible growth */
247 bufsz
+= GROWTH_ALLOWANCE
;
249 fault
->pplainio
.buf
= cur
= OPENSSL_malloc(bufsz
);
251 fault
->pplainio
.buf_len
= 0;
255 fault
->pplainbuf_alloc
= bufsz
;
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
;
263 fault
->pplainhdr
= *hdrin
;
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
))
272 *hdrout
= &fault
->pplainhdr
;
273 *iovecout
= &fault
->pplainio
;
279 static void packet_plain_finish(void *arg
)
281 OSSL_QUIC_FAULT
*fault
= arg
;
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
;
290 int ossl_quic_fault_set_packet_plain_listener(OSSL_QUIC_FAULT
*fault
,
291 ossl_quic_fault_on_packet_plain_cb pplaincb
,
294 fault
->pplaincb
= pplaincb
;
295 fault
->pplaincbarg
= pplaincbarg
;
297 return ossl_quic_tserver_set_plain_packet_mutator(fault
->qtserv
,
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
)
307 size_t oldlen
= fault
->pplainio
.buf_len
;
310 * Alloc'd size should always be non-zero, so if this fails we've been
313 if (fault
->pplainbuf_alloc
== 0)
316 if (newlen
> fault
->pplainbuf_alloc
) {
317 /* This exceeds our growth allowance. Fail */
321 /* Cast below is safe because we allocated the buffer */
322 buf
= (unsigned char *)fault
->pplainio
.buf
;
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 */
329 fault
->pplainio
.buf_len
= newlen
;
330 fault
->pplainhdr
.len
= newlen
;
335 static int handshake_mutate(const unsigned char *msgin
, size_t msginlen
,
336 unsigned char **msgout
, size_t *msgoutlen
,
339 OSSL_QUIC_FAULT
*fault
= arg
;
341 unsigned long payloadlen
;
342 unsigned int msgtype
;
345 buf
= OPENSSL_malloc(msginlen
+ GROWTH_ALLOWANCE
);
349 fault
->handbuf
= buf
;
350 fault
->handbuflen
= msginlen
;
351 fault
->handbufalloc
= msginlen
+ GROWTH_ALLOWANCE
;
352 memcpy(buf
, msgin
, msginlen
);
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
)
360 /* Parse specific message types */
362 case SSL3_MT_ENCRYPTED_EXTENSIONS
:
364 OSSL_QF_ENCRYPTED_EXTENSIONS ee
;
366 if (fault
->encextcb
== NULL
)
370 * The EncryptedExtensions message is very simple. It just has an
371 * extensions block in it and nothing else.
373 ee
.extensions
= (unsigned char *)PACKET_data(&pkt
);
374 ee
.extensionslen
= payloadlen
;
375 if (!fault
->encextcb(fault
, &ee
, payloadlen
, fault
->encextcbarg
))
380 /* No specific handlers for these message types yet */
384 if (fault
->handshakecb
!= NULL
385 && !fault
->handshakecb(fault
, buf
, fault
->handbuflen
,
386 fault
->handshakecbarg
))
390 *msgoutlen
= fault
->handbuflen
;
395 static void handshake_finish(void *arg
)
397 OSSL_QUIC_FAULT
*fault
= arg
;
399 OPENSSL_free(fault
->handbuf
);
400 fault
->handbuf
= NULL
;
403 int ossl_quic_fault_set_handshake_listener(OSSL_QUIC_FAULT
*fault
,
404 ossl_quic_fault_on_handshake_cb handshakecb
,
405 void *handshakecbarg
)
407 fault
->handshakecb
= handshakecb
;
408 fault
->handshakecbarg
= handshakecbarg
;
410 return ossl_quic_tserver_set_handshake_mutator(fault
->qtserv
,
416 int ossl_quic_fault_set_hand_enc_ext_listener(OSSL_QUIC_FAULT
*fault
,
417 ossl_quic_fault_on_enc_ext_cb encextcb
,
420 fault
->encextcb
= encextcb
;
421 fault
->encextcbarg
= encextcbarg
;
423 return ossl_quic_tserver_set_handshake_mutator(fault
->qtserv
,
429 /* To be called from a handshake_listener callback */
430 int ossl_quic_fault_resize_handshake(OSSL_QUIC_FAULT
*fault
, size_t newlen
)
433 size_t oldlen
= fault
->handbuflen
;
436 * Alloc'd size should always be non-zero, so if this fails we've been
439 if (fault
->handbufalloc
== 0)
442 if (newlen
> fault
->handbufalloc
) {
443 /* This exceeds our growth allowance. Fail */
447 buf
= (unsigned char *)fault
->handbuf
;
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 */
454 fault
->handbuflen
= newlen
;
458 /* To be called from message specific listener callbacks */
459 int ossl_quic_fault_resize_message(OSSL_QUIC_FAULT
*fault
, size_t newlen
)
461 /* First resize the underlying message */
462 if (!ossl_quic_fault_resize_handshake(fault
, newlen
+ SSL3_HM_HEADER_LENGTH
))
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);
473 int ossl_quic_fault_delete_extension(OSSL_QUIC_FAULT
*fault
,
474 unsigned int exttype
, unsigned char *ext
,
477 PACKET pkt
, sub
, subext
;
479 const unsigned char *start
, *end
;
481 size_t msglen
= fault
->handbuflen
;
483 if (!PACKET_buf_init(&pkt
, ext
, *extlen
))
486 /* Extension block starts with 2 bytes for extension block length */
487 if (!PACKET_as_length_prefixed_2(&pkt
, &sub
))
491 start
= PACKET_data(&sub
);
492 if (!PACKET_get_net_2(&sub
, &type
)
493 || !PACKET_get_length_prefixed_2(&sub
, &subext
))
495 } while (type
!= exttype
);
498 end
= PACKET_data(&sub
);
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.
505 if (end
< ext
+ *extlen
)
506 memmove((unsigned char *)start
, end
, end
- start
);
509 * Calculate new extensions payload length =
511 * - 2 extension block length bytes
512 * - length of removed extension
514 newlen
= *extlen
- 2 - (end
- start
);
516 /* Fixup the length bytes for the extension block */
517 ext
[0] = (unsigned char)((newlen
>> 8) & 0xff);
518 ext
[1] = (unsigned char)((newlen
) & 0xff);
521 * Length of the whole extension block is the new payload length plus the
522 * 2 bytes for the length
524 *extlen
= newlen
+ 2;
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
))
536 #define BIO_TYPE_CIPHER_PACKET_FILTER (0x80 | BIO_TYPE_FILTER)
538 static BIO_METHOD
*pcipherbiometh
= NULL
;
540 # define BIO_MSG_N(array, stride, n) (*(BIO_MSG *)((char *)(array) + (n)*(stride)))
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
)
546 OSSL_QUIC_FAULT
*fault
;
547 BIO
*next
= BIO_next(b
);
548 ossl_ssize_t ret
= 0;
550 size_t i
= 0, tmpnump
;
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
);
568 for (i
= 0; i
< num_msg
; ++i
) {
569 m
= BIO_MSG_N(msg
, stride
, i
);
571 /* Take a copy of the data so that callbacks can modify it */
572 m
.data
= OPENSSL_memdup(m
.data
, m
.data_len
);
576 if (!PACKET_buf_init(&pkt
, m
.data
, m
.data_len
))
580 if (!ossl_quic_wire_decode_pkt_hdr(&pkt
,
581 0/* TODO(QUIC): Not sure how this should be set*/, 1, &hdr
,
585 /* TODO(QUIC): Resolve const issue here */
586 if (!fault
->pciphercb(fault
, &hdr
, (unsigned char *)hdr
.data
,
587 hdr
.len
, fault
->pciphercbarg
))
589 } while (PACKET_remaining(&pkt
) > 0);
591 if (!BIO_sendmmsg(next
, &m
, stride
, 1, flags
, &tmpnump
)) {
596 OPENSSL_free(m
.data
);
607 OPENSSL_free(m
.data
);
611 static long pcipher_ctrl(BIO
*b
, int cmd
, long larg
, void *parg
)
613 BIO
*next
= BIO_next(b
);
618 return BIO_ctrl(next
, cmd
, larg
, parg
);
621 static BIO_METHOD
*get_bio_method(void)
625 if (pcipherbiometh
!= NULL
)
626 return pcipherbiometh
;
628 tmp
= BIO_meth_new(BIO_TYPE_CIPHER_PACKET_FILTER
, "Cipher Packet Filter");
633 if (!TEST_true(BIO_meth_set_sendmmsg(tmp
, pcipher_sendmmsg
))
634 || !TEST_true(BIO_meth_set_ctrl(tmp
, pcipher_ctrl
)))
637 pcipherbiometh
= tmp
;
641 return pcipherbiometh
;
644 int ossl_quic_fault_set_packet_cipher_listener(OSSL_QUIC_FAULT
*fault
,
645 ossl_quic_fault_on_packet_cipher_cb pciphercb
,
648 fault
->pciphercb
= pciphercb
;
649 fault
->pciphercbarg
= pciphercbarg
;