xref: /freebsd/crypto/openssl/test/helpers/quictestlib.h (revision e7be843b4a162e68651d3911f0357ed464915629)
1*e7be843bSPierre Pronchery /*
2*e7be843bSPierre Pronchery  * Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved.
3*e7be843bSPierre Pronchery  *
4*e7be843bSPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5*e7be843bSPierre Pronchery  * this file except in compliance with the License.  You can obtain a copy
6*e7be843bSPierre Pronchery  * in the file LICENSE in the source distribution or at
7*e7be843bSPierre Pronchery  * https://www.openssl.org/source/license.html
8*e7be843bSPierre Pronchery  */
9*e7be843bSPierre Pronchery 
10*e7be843bSPierre Pronchery #include <openssl/ssl.h>
11*e7be843bSPierre Pronchery #include <internal/quic_tserver.h>
12*e7be843bSPierre Pronchery 
13*e7be843bSPierre Pronchery /* Type to represent the Fault Injector */
14*e7be843bSPierre Pronchery typedef struct qtest_fault QTEST_FAULT;
15*e7be843bSPierre Pronchery 
16*e7be843bSPierre Pronchery typedef struct bio_qtest_data {
17*e7be843bSPierre Pronchery     size_t short_conn_id_len;
18*e7be843bSPierre Pronchery     struct qtest_fault *fault;
19*e7be843bSPierre Pronchery } QTEST_DATA;
20*e7be843bSPierre Pronchery 
21*e7be843bSPierre Pronchery /*
22*e7be843bSPierre Pronchery  * Structure representing a parsed EncryptedExtension message. Listeners can
23*e7be843bSPierre Pronchery  * make changes to the contents of structure objects as required and the fault
24*e7be843bSPierre Pronchery  * injector will reconstruct the message to be sent on
25*e7be843bSPierre Pronchery  */
26*e7be843bSPierre Pronchery typedef struct qtest_fault_encrypted_extensions {
27*e7be843bSPierre Pronchery     /* EncryptedExtension messages just have an extensions block */
28*e7be843bSPierre Pronchery     unsigned char *extensions;
29*e7be843bSPierre Pronchery     size_t extensionslen;
30*e7be843bSPierre Pronchery } QTEST_ENCRYPTED_EXTENSIONS;
31*e7be843bSPierre Pronchery 
32*e7be843bSPierre Pronchery /* Flags for use with qtest_create_quic_objects() */
33*e7be843bSPierre Pronchery 
34*e7be843bSPierre Pronchery /* Indicates whether we are using blocking mode or not */
35*e7be843bSPierre Pronchery #define QTEST_FLAG_BLOCK        (1 << 0)
36*e7be843bSPierre Pronchery /* Use fake time rather than real time */
37*e7be843bSPierre Pronchery #define QTEST_FLAG_FAKE_TIME    (1 << 1)
38*e7be843bSPierre Pronchery /* Introduce noise in the BIO */
39*e7be843bSPierre Pronchery #define QTEST_FLAG_NOISE        (1 << 2)
40*e7be843bSPierre Pronchery /* Split datagrams such that each datagram contains one packet */
41*e7be843bSPierre Pronchery #define QTEST_FLAG_PACKET_SPLIT (1 << 3)
42*e7be843bSPierre Pronchery /* Turn on client side tracing */
43*e7be843bSPierre Pronchery #define QTEST_FLAG_CLIENT_TRACE (1 << 4)
44*e7be843bSPierre Pronchery /*
45*e7be843bSPierre Pronchery  * Given an SSL_CTX for the client and filenames for the server certificate and
46*e7be843bSPierre Pronchery  * keyfile, create a server and client instances as well as a fault injector
47*e7be843bSPierre Pronchery  * instance. |flags| is the logical or of flags defined above, or 0 if none.
48*e7be843bSPierre Pronchery  */
49*e7be843bSPierre Pronchery int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx,
50*e7be843bSPierre Pronchery                               SSL_CTX *serverctx, char *certfile, char *keyfile,
51*e7be843bSPierre Pronchery                               int flags, QUIC_TSERVER **qtserv, SSL **cssl,
52*e7be843bSPierre Pronchery                               QTEST_FAULT **fault, BIO **tracebio);
53*e7be843bSPierre Pronchery 
54*e7be843bSPierre Pronchery /* Where QTEST_FLAG_FAKE_TIME is used, add millis to the current time */
55*e7be843bSPierre Pronchery void qtest_add_time(uint64_t millis);
56*e7be843bSPierre Pronchery 
57*e7be843bSPierre Pronchery /* Starts time measurement */
58*e7be843bSPierre Pronchery void qtest_start_stopwatch(void);
59*e7be843bSPierre Pronchery /* Returns the duration from the start in millis */
60*e7be843bSPierre Pronchery uint64_t qtest_get_stopwatch_time(void);
61*e7be843bSPierre Pronchery 
62*e7be843bSPierre Pronchery QTEST_FAULT *qtest_create_injector(QUIC_TSERVER *ts);
63*e7be843bSPierre Pronchery 
64*e7be843bSPierre Pronchery BIO_METHOD *qtest_get_bio_method(void);
65*e7be843bSPierre Pronchery 
66*e7be843bSPierre Pronchery /*
67*e7be843bSPierre Pronchery  * Free up a Fault Injector instance
68*e7be843bSPierre Pronchery  */
69*e7be843bSPierre Pronchery void qtest_fault_free(QTEST_FAULT *fault);
70*e7be843bSPierre Pronchery 
71*e7be843bSPierre Pronchery /* Returns 1 if the quictestlib supports blocking tests */
72*e7be843bSPierre Pronchery int qtest_supports_blocking(void);
73*e7be843bSPierre Pronchery 
74*e7be843bSPierre Pronchery /*
75*e7be843bSPierre Pronchery  * Run the TLS handshake to create a QUIC connection between the client and
76*e7be843bSPierre Pronchery  * server.
77*e7be843bSPierre Pronchery  */
78*e7be843bSPierre Pronchery int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl);
79*e7be843bSPierre Pronchery 
80*e7be843bSPierre Pronchery /*
81*e7be843bSPierre Pronchery  * Check if both client and server have no data to read and are waiting on a
82*e7be843bSPierre Pronchery  * timeout. If so, wait until the timeout has expired.
83*e7be843bSPierre Pronchery  */
84*e7be843bSPierre Pronchery int qtest_wait_for_timeout(SSL *s, QUIC_TSERVER *qtserv);
85*e7be843bSPierre Pronchery 
86*e7be843bSPierre Pronchery /*
87*e7be843bSPierre Pronchery  * Same as qtest_create_quic_connection but will stop (successfully) if the
88*e7be843bSPierre Pronchery  * clientssl indicates SSL_ERROR_WANT_XXX as specified by |wanterr|
89*e7be843bSPierre Pronchery  */
90*e7be843bSPierre Pronchery int qtest_create_quic_connection_ex(QUIC_TSERVER *qtserv, SSL *clientssl,
91*e7be843bSPierre Pronchery                                     int wanterr);
92*e7be843bSPierre Pronchery 
93*e7be843bSPierre Pronchery /*
94*e7be843bSPierre Pronchery  * Shutdown the client SSL object gracefully
95*e7be843bSPierre Pronchery  */
96*e7be843bSPierre Pronchery int qtest_shutdown(QUIC_TSERVER *qtserv, SSL *clientssl);
97*e7be843bSPierre Pronchery 
98*e7be843bSPierre Pronchery /*
99*e7be843bSPierre Pronchery  * Confirm that the server has received the given transport error code.
100*e7be843bSPierre Pronchery  */
101*e7be843bSPierre Pronchery int qtest_check_server_transport_err(QUIC_TSERVER *qtserv, uint64_t code);
102*e7be843bSPierre Pronchery 
103*e7be843bSPierre Pronchery /*
104*e7be843bSPierre Pronchery  * Confirm the server has received a protocol error. Equivalent to calling
105*e7be843bSPierre Pronchery  * qtest_check_server_transport_err with a code of QUIC_ERR_PROTOCOL_VIOLATION
106*e7be843bSPierre Pronchery  */
107*e7be843bSPierre Pronchery int qtest_check_server_protocol_err(QUIC_TSERVER *qtserv);
108*e7be843bSPierre Pronchery 
109*e7be843bSPierre Pronchery /*
110*e7be843bSPierre Pronchery  * Confirm the server has received a frame encoding error. Equivalent to calling
111*e7be843bSPierre Pronchery  * qtest_check_server_transport_err with a code of QUIC_ERR_FRAME_ENCODING_ERROR
112*e7be843bSPierre Pronchery  */
113*e7be843bSPierre Pronchery int qtest_check_server_frame_encoding_err(QUIC_TSERVER *qtserv);
114*e7be843bSPierre Pronchery 
115*e7be843bSPierre Pronchery /*
116*e7be843bSPierre Pronchery  * Enable tests to listen for pre-encryption QUIC packets being sent
117*e7be843bSPierre Pronchery  */
118*e7be843bSPierre Pronchery typedef int (*qtest_fault_on_packet_plain_cb)(QTEST_FAULT *fault,
119*e7be843bSPierre Pronchery                                               QUIC_PKT_HDR *hdr,
120*e7be843bSPierre Pronchery                                               unsigned char *buf,
121*e7be843bSPierre Pronchery                                               size_t len,
122*e7be843bSPierre Pronchery                                               void *cbarg);
123*e7be843bSPierre Pronchery 
124*e7be843bSPierre Pronchery int qtest_fault_set_packet_plain_listener(QTEST_FAULT *fault,
125*e7be843bSPierre Pronchery                                           qtest_fault_on_packet_plain_cb pplaincb,
126*e7be843bSPierre Pronchery                                           void *pplaincbarg);
127*e7be843bSPierre Pronchery 
128*e7be843bSPierre Pronchery 
129*e7be843bSPierre Pronchery /*
130*e7be843bSPierre Pronchery  * Helper function to be called from a packet_plain_listener callback if it
131*e7be843bSPierre Pronchery  * wants to resize the packet (either to add new data to it, or to truncate it).
132*e7be843bSPierre Pronchery  * The buf provided to packet_plain_listener is over allocated, so this just
133*e7be843bSPierre Pronchery  * changes the logical size and never changes the actual address of the buf.
134*e7be843bSPierre Pronchery  * This will fail if a large resize is attempted that exceeds the over
135*e7be843bSPierre Pronchery  * allocation.
136*e7be843bSPierre Pronchery  */
137*e7be843bSPierre Pronchery int qtest_fault_resize_plain_packet(QTEST_FAULT *fault, size_t newlen);
138*e7be843bSPierre Pronchery 
139*e7be843bSPierre Pronchery /*
140*e7be843bSPierre Pronchery  * Prepend frame data into a packet. To be called from a packet_plain_listener
141*e7be843bSPierre Pronchery  * callback
142*e7be843bSPierre Pronchery  */
143*e7be843bSPierre Pronchery int qtest_fault_prepend_frame(QTEST_FAULT *fault, const unsigned char *frame,
144*e7be843bSPierre Pronchery                               size_t frame_len);
145*e7be843bSPierre Pronchery 
146*e7be843bSPierre Pronchery /*
147*e7be843bSPierre Pronchery  * The general handshake message listener is sent the entire handshake message
148*e7be843bSPierre Pronchery  * data block, including the handshake header itself
149*e7be843bSPierre Pronchery  */
150*e7be843bSPierre Pronchery typedef int (*qtest_fault_on_handshake_cb)(QTEST_FAULT *fault,
151*e7be843bSPierre Pronchery                                            unsigned char *msg,
152*e7be843bSPierre Pronchery                                            size_t msglen,
153*e7be843bSPierre Pronchery                                            void *handshakecbarg);
154*e7be843bSPierre Pronchery 
155*e7be843bSPierre Pronchery int qtest_fault_set_handshake_listener(QTEST_FAULT *fault,
156*e7be843bSPierre Pronchery                                        qtest_fault_on_handshake_cb handshakecb,
157*e7be843bSPierre Pronchery                                        void *handshakecbarg);
158*e7be843bSPierre Pronchery 
159*e7be843bSPierre Pronchery /*
160*e7be843bSPierre Pronchery  * Helper function to be called from a handshake_listener callback if it wants
161*e7be843bSPierre Pronchery  * to resize the handshake message (either to add new data to it, or to truncate
162*e7be843bSPierre Pronchery  * it). newlen must include the length of the handshake message header. The
163*e7be843bSPierre Pronchery  * handshake message buffer is over allocated, so this just changes the logical
164*e7be843bSPierre Pronchery  * size and never changes the actual address of the buf.
165*e7be843bSPierre Pronchery  * This will fail if a large resize is attempted that exceeds the over
166*e7be843bSPierre Pronchery  * allocation.
167*e7be843bSPierre Pronchery  */
168*e7be843bSPierre Pronchery int qtest_fault_resize_handshake(QTEST_FAULT *fault, size_t newlen);
169*e7be843bSPierre Pronchery 
170*e7be843bSPierre Pronchery /*
171*e7be843bSPierre Pronchery  * Add listeners for specific types of frame here. E.g. we might
172*e7be843bSPierre Pronchery  * expect to see an "ACK" frame listener which will be passed pre-parsed ack
173*e7be843bSPierre Pronchery  * data that can be modified as required.
174*e7be843bSPierre Pronchery  */
175*e7be843bSPierre Pronchery 
176*e7be843bSPierre Pronchery /*
177*e7be843bSPierre Pronchery  * Handshake message specific listeners. Unlike the general handshake message
178*e7be843bSPierre Pronchery  * listener these messages are pre-parsed and supplied with message specific
179*e7be843bSPierre Pronchery  * data and exclude the handshake header
180*e7be843bSPierre Pronchery  */
181*e7be843bSPierre Pronchery typedef int (*qtest_fault_on_enc_ext_cb)(QTEST_FAULT *fault,
182*e7be843bSPierre Pronchery                                          QTEST_ENCRYPTED_EXTENSIONS *ee,
183*e7be843bSPierre Pronchery                                          size_t eelen,
184*e7be843bSPierre Pronchery                                          void *encextcbarg);
185*e7be843bSPierre Pronchery 
186*e7be843bSPierre Pronchery int qtest_fault_set_hand_enc_ext_listener(QTEST_FAULT *fault,
187*e7be843bSPierre Pronchery                                           qtest_fault_on_enc_ext_cb encextcb,
188*e7be843bSPierre Pronchery                                           void *encextcbarg);
189*e7be843bSPierre Pronchery 
190*e7be843bSPierre Pronchery /* Add listeners for other types of handshake message here */
191*e7be843bSPierre Pronchery 
192*e7be843bSPierre Pronchery 
193*e7be843bSPierre Pronchery /*
194*e7be843bSPierre Pronchery  * Helper function to be called from message specific listener callbacks. newlen
195*e7be843bSPierre Pronchery  * is the new length of the specific message excluding the handshake message
196*e7be843bSPierre Pronchery  * header.  The buffers provided to the message specific listeners are over
197*e7be843bSPierre Pronchery  * allocated, so this just changes the logical size and never changes the actual
198*e7be843bSPierre Pronchery  * address of the buffer. This will fail if a large resize is attempted that
199*e7be843bSPierre Pronchery  * exceeds the over allocation.
200*e7be843bSPierre Pronchery  */
201*e7be843bSPierre Pronchery int qtest_fault_resize_message(QTEST_FAULT *fault, size_t newlen);
202*e7be843bSPierre Pronchery 
203*e7be843bSPierre Pronchery /*
204*e7be843bSPierre Pronchery  * Helper function to delete an extension from an extension block. |exttype| is
205*e7be843bSPierre Pronchery  * the type of the extension to be deleted. |ext| points to the extension block.
206*e7be843bSPierre Pronchery  * On entry |*extlen| contains the length of the extension block. It is updated
207*e7be843bSPierre Pronchery  * with the new length on exit. If old_ext is non-NULL, the deleted extension
208*e7be843bSPierre Pronchery  * is appended to the given BUF_MEM.
209*e7be843bSPierre Pronchery  */
210*e7be843bSPierre Pronchery int qtest_fault_delete_extension(QTEST_FAULT *fault,
211*e7be843bSPierre Pronchery                                  unsigned int exttype, unsigned char *ext,
212*e7be843bSPierre Pronchery                                  size_t *extlen,
213*e7be843bSPierre Pronchery                                  BUF_MEM *old_ext);
214*e7be843bSPierre Pronchery 
215*e7be843bSPierre Pronchery /*
216*e7be843bSPierre Pronchery  * Add additional helper functions for querying extensions here (e.g.
217*e7be843bSPierre Pronchery  * finding or adding them). We could also provide a "listener" API for listening
218*e7be843bSPierre Pronchery  * for specific extension types
219*e7be843bSPierre Pronchery  */
220*e7be843bSPierre Pronchery 
221*e7be843bSPierre Pronchery /*
222*e7be843bSPierre Pronchery  * Enable tests to listen for post-encryption QUIC packets being sent
223*e7be843bSPierre Pronchery  */
224*e7be843bSPierre Pronchery typedef int (*qtest_fault_on_packet_cipher_cb)(QTEST_FAULT *fault,
225*e7be843bSPierre Pronchery                                                /* The parsed packet header */
226*e7be843bSPierre Pronchery                                                QUIC_PKT_HDR *hdr,
227*e7be843bSPierre Pronchery                                                /* The packet payload data */
228*e7be843bSPierre Pronchery                                                unsigned char *buf,
229*e7be843bSPierre Pronchery                                                /* Length of the payload */
230*e7be843bSPierre Pronchery                                                size_t len,
231*e7be843bSPierre Pronchery                                                void *cbarg);
232*e7be843bSPierre Pronchery 
233*e7be843bSPierre Pronchery int qtest_fault_set_packet_cipher_listener(QTEST_FAULT *fault,
234*e7be843bSPierre Pronchery                                            qtest_fault_on_packet_cipher_cb pciphercb,
235*e7be843bSPierre Pronchery                                            void *picphercbarg);
236*e7be843bSPierre Pronchery 
237*e7be843bSPierre Pronchery /*
238*e7be843bSPierre Pronchery  * Enable tests to listen for datagrams being sent
239*e7be843bSPierre Pronchery  */
240*e7be843bSPierre Pronchery typedef int (*qtest_fault_on_datagram_cb)(QTEST_FAULT *fault,
241*e7be843bSPierre Pronchery                                           BIO_MSG *m,
242*e7be843bSPierre Pronchery                                           size_t stride,
243*e7be843bSPierre Pronchery                                           void *cbarg);
244*e7be843bSPierre Pronchery 
245*e7be843bSPierre Pronchery int qtest_fault_set_datagram_listener(QTEST_FAULT *fault,
246*e7be843bSPierre Pronchery                                       qtest_fault_on_datagram_cb datagramcb,
247*e7be843bSPierre Pronchery                                       void *datagramcbarg);
248*e7be843bSPierre Pronchery 
249*e7be843bSPierre Pronchery /*
250*e7be843bSPierre Pronchery  * To be called from a datagram_listener callback. The datagram buffer is over
251*e7be843bSPierre Pronchery  * allocated, so this just changes the logical size and never changes the actual
252*e7be843bSPierre Pronchery  * address of the buffer. This will fail if a large resize is attempted that
253*e7be843bSPierre Pronchery  * exceeds the over allocation.
254*e7be843bSPierre Pronchery  */
255*e7be843bSPierre Pronchery int qtest_fault_resize_datagram(QTEST_FAULT *fault, size_t newlen);
256*e7be843bSPierre Pronchery 
257*e7be843bSPierre Pronchery /*
258*e7be843bSPierre Pronchery  * Set bandwidth and noise rate on noisy dgram filter.
259*e7be843bSPierre Pronchery  * Arguments with values of 0 mean no limit/no noise.
260*e7be843bSPierre Pronchery  */
261*e7be843bSPierre Pronchery 
262*e7be843bSPierre Pronchery int qtest_fault_set_bw_limit(QTEST_FAULT *fault,
263*e7be843bSPierre Pronchery                              size_t ctos_bw, size_t stoc_bw,
264*e7be843bSPierre Pronchery                              int noise_rate);
265*e7be843bSPierre Pronchery 
266*e7be843bSPierre Pronchery /* Copy a BIO_MSG */
267*e7be843bSPierre Pronchery int bio_msg_copy(BIO_MSG *dst, BIO_MSG *src);
268*e7be843bSPierre Pronchery 
269*e7be843bSPierre Pronchery #define BIO_CTRL_NOISE_BACK_OFF       1001
270*e7be843bSPierre Pronchery #define BIO_CTRL_NOISE_RATE           1002
271*e7be843bSPierre Pronchery #define BIO_CTRL_NOISE_RECV_BANDWIDTH 1003
272*e7be843bSPierre Pronchery #define BIO_CTRL_NOISE_SEND_BANDWIDTH 1004
273*e7be843bSPierre Pronchery #define BIO_CTRL_NOISE_SET_NOW_CB     1005
274*e7be843bSPierre Pronchery 
275*e7be843bSPierre Pronchery struct bio_noise_now_cb_st {
276*e7be843bSPierre Pronchery     OSSL_TIME (*now_cb)(void *);
277*e7be843bSPierre Pronchery     void *now_cb_arg;
278*e7be843bSPierre Pronchery };
279*e7be843bSPierre Pronchery 
280*e7be843bSPierre Pronchery /* BIO filter for simulating a noisy UDP socket */
281*e7be843bSPierre Pronchery const BIO_METHOD *bio_f_noisy_dgram_filter(void);
282*e7be843bSPierre Pronchery 
283*e7be843bSPierre Pronchery /* Free the BIO filter method object */
284*e7be843bSPierre Pronchery void bio_f_noisy_dgram_filter_free(void);
285*e7be843bSPierre Pronchery 
286*e7be843bSPierre Pronchery /*
287*e7be843bSPierre Pronchery  * BIO filter for splitting QUIC datagrams containing multiple packets into
288*e7be843bSPierre Pronchery  * individual datagrams.
289*e7be843bSPierre Pronchery  */
290*e7be843bSPierre Pronchery const BIO_METHOD *bio_f_pkt_split_dgram_filter(void);
291*e7be843bSPierre Pronchery 
292*e7be843bSPierre Pronchery /* Free the BIO filter method object */
293*e7be843bSPierre Pronchery void bio_f_pkt_split_dgram_filter_free(void);
294