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