summaryrefslogtreecommitdiffstats
path: root/test/helpers/quictestlib.h
blob: 228d396f41c25c73d9333e8d324d1e06d90b52b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/*
 * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the Apache License 2.0 (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
 */

#include <openssl/ssl.h>
#include <internal/quic_tserver.h>

/* Type to represent the Fault Injector */
typedef struct qtest_fault QTEST_FAULT;

/*
 * Structure representing a parsed EncryptedExtension message. Listeners can
 * make changes to the contents of structure objects as required and the fault
 * injector will reconstruct the message to be sent on
 */
typedef struct qtest_fault_encrypted_extensions {
    /* EncryptedExtension messages just have an extensions block */
    unsigned char *extensions;
    size_t extensionslen;
} QTEST_ENCRYPTED_EXTENSIONS;

/* Flags for use with qtest_create_quic_objects() */

/* Indicates whether we are using blocking mode or not */
#define QTEST_FLAG_BLOCK        (1 << 0)
/* Use fake time rather than real time */
#define QTEST_FLAG_FAKE_TIME    (1 << 1)
/* Introduce noise in the BIO */
#define QTEST_FLAG_NOISE        (1 << 2)
/* Split datagrams such that each datagram contains one packet */
#define QTEST_FLAG_PACKET_SPLIT (1 << 3)
/* Turn on client side tracing */
#define QTEST_FLAG_CLIENT_TRACE (1 << 4)
/*
 * Given an SSL_CTX for the client and filenames for the server certificate and
 * keyfile, create a server and client instances as well as a fault injector
 * instance. |flags| is the logical or of flags defined above, or 0 if none.
 */
int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx,
                              SSL_CTX *serverctx, char *certfile, char *keyfile,
                              int flags, QUIC_TSERVER **qtserv, SSL **cssl,
                              QTEST_FAULT **fault, BIO **tracebio);

/* Where QTEST_FLAG_FAKE_TIME is used, add millis to the current time */
void qtest_add_time(uint64_t millis);

QTEST_FAULT *qtest_create_injector(QUIC_TSERVER *ts);

BIO_METHOD *qtest_get_bio_method(void);

/*
 * Free up a Fault Injector instance
 */
void qtest_fault_free(QTEST_FAULT *fault);

/* Returns 1 if the quictestlib supports blocking tests */
int qtest_supports_blocking(void);

/*
 * Run the TLS handshake to create a QUIC connection between the client and
 * server.
 */
int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl);

/*
 * Check if both client and server have no data to read and are waiting on a
 * timeout. If so, wait until the timeout has expired.
 */
int qtest_wait_for_timeout(SSL *s, QUIC_TSERVER *qtserv);

/*
 * Same as qtest_create_quic_connection but will stop (successfully) if the
 * clientssl indicates SSL_ERROR_WANT_XXX as specified by |wanterr|
 */
int qtest_create_quic_connection_ex(QUIC_TSERVER *qtserv, SSL *clientssl,
                                    int wanterr);

/*
 * Shutdown the client SSL object gracefully
 */
int qtest_shutdown(QUIC_TSERVER *qtserv, SSL *clientssl);

/*
 * Confirm that the server has received the given transport error code.
 */
int qtest_check_server_transport_err(QUIC_TSERVER *qtserv, uint64_t code);

/*
 * Confirm the server has received a protocol error. Equivalent to calling
 * qtest_check_server_transport_err with a code of QUIC_ERR_PROTOCOL_VIOLATION
 */
int qtest_check_server_protocol_err(QUIC_TSERVER *qtserv);

/*
 * Confirm the server has received a frame encoding error. Equivalent to calling
 * qtest_check_server_transport_err with a code of QUIC_ERR_FRAME_ENCODING_ERROR
 */
int qtest_check_server_frame_encoding_err(QUIC_TSERVER *qtserv);

/*
 * Enable tests to listen for pre-encryption QUIC packets being sent
 */
typedef int (*qtest_fault_on_packet_plain_cb)(QTEST_FAULT *fault,
                                              QUIC_PKT_HDR *hdr,
                                              unsigned char *buf,
                                              size_t len,
                                              void *cbarg);

int qtest_fault_set_packet_plain_listener(QTEST_FAULT *fault,
                                          qtest_fault_on_packet_plain_cb pplaincb,
                                          void *pplaincbarg);


/*
 * Helper function to be called from a packet_plain_listener callback if it
 * wants to resize the packet (either to add new data to it, or to truncate it).
 * The buf provided to packet_plain_listener is over allocated, so this just
 * changes the logical size and never changes the actual address of the buf.
 * This will fail if a large resize is attempted that exceeds the over
 * allocation.
 */
int qtest_fault_resize_plain_packet(QTEST_FAULT *fault, size_t newlen);

/*
 * Prepend frame data into a packet. To be called from a packet_plain_listener
 * callback
 */
int qtest_fault_prepend_frame(QTEST_FAULT *fault, const unsigned char *frame,
                              size_t frame_len);

/*
 * The general handshake message listener is sent the entire handshake message
 * data block, including the handshake header itself
 */
typedef int (*qtest_fault_on_handshake_cb)(QTEST_FAULT *fault,
                                           unsigned char *msg,
                                           size_t msglen,
                                           void *handshakecbarg);

int qtest_fault_set_handshake_listener(QTEST_FAULT *fault,
                                       qtest_fault_on_handshake_cb handshakecb,
                                       void *handshakecbarg);

/*
 * Helper function to be called from a handshake_listener callback if it wants
 * to resize the handshake message (either to add new data to it, or to truncate
 * it). newlen must include the length of the handshake message header. The
 * handshake message buffer is over allocated, so this just changes the logical
 * size and never changes the actual address of the buf.
 * This will fail if a large resize is attempted that exceeds the over
 * allocation.
 */
int qtest_fault_resize_handshake(QTEST_FAULT *fault, size_t newlen);

/*
 * Add listeners for specific types of frame here. E.g. we might
 * expect to see an "ACK" frame listener which will be passed pre-parsed ack
 * data that can be modified as required.
 */

/*
 * Handshake message specific listeners. Unlike the general handshake message
 * listener these messages are pre-parsed and supplied with message specific
 * data and exclude the handshake header
 */
typedef int (*qtest_fault_on_enc_ext_cb)(QTEST_FAULT *fault,
                                         QTEST_ENCRYPTED_EXTENSIONS *ee,
                                         size_t eelen,
                                         void *encextcbarg);

int qtest_fault_set_hand_enc_ext_listener(QTEST_FAULT *fault,
                                          qtest_fault_on_enc_ext_cb encextcb,
                                          void *encextcbarg);

/* Add listeners for other types of handshake message here */


/*
 * Helper function to be called from message specific listener callbacks. newlen
 * is the new length of the specific message excluding the handshake message
 * header.  The buffers provided to the message specific listeners are over
 * allocated, so this just changes the logical size and never changes the actual
 * address of the buffer. This will fail if a large resize is attempted that
 * exceeds the over allocation.
 */
int qtest_fault_resize_message(QTEST_FAULT *fault, size_t newlen);

/*
 * Helper function to delete an extension from an extension block. |exttype| is
 * the type of the extension to be deleted. |ext| points to the extension block.
 * On entry |*extlen| contains the length of the extension block. It is updated
 * with the new length on exit. If old_ext is non-NULL, the deleted extension
 * is appended to the given BUF_MEM.
 */
int qtest_fault_delete_extension(QTEST_FAULT *fault,
                                 unsigned int exttype, unsigned char *ext,
                                 size_t *extlen,
                                 BUF_MEM *old_ext);

/*
 * Add additional helper functions for querying extensions here (e.g.
 * finding or adding them). We could also provide a "listener" API for listening
 * for specific extension types
 */

/*
 * Enable tests to listen for post-encryption QUIC packets being sent
 */
typedef int (*qtest_fault_on_packet_cipher_cb)(QTEST_FAULT *fault,
                                               /* The parsed packet header */
                                               QUIC_PKT_HDR *hdr,
                                               /* The packet payload data */
                                               unsigned char *buf,
                                               /* Length of the payload */
                                               size_t len,
                                               void *cbarg);

int qtest_fault_set_packet_cipher_listener(QTEST_FAULT *fault,
                                           qtest_fault_on_packet_cipher_cb pciphercb,
                                           void *picphercbarg);

/*
 * Enable tests to listen for datagrams being sent
 */
typedef int (*qtest_fault_on_datagram_cb)(QTEST_FAULT *fault,
                                          BIO_MSG *m,
                                          size_t stride,
                                          void *cbarg);

int qtest_fault_set_datagram_listener(QTEST_FAULT *fault,
                                      qtest_fault_on_datagram_cb datagramcb,
                                      void *datagramcbarg);

/*
 * To be called from a datagram_listener callback. The datagram buffer is over
 * allocated, so this just changes the logical size and never changes the actual
 * address of the buffer. This will fail if a large resize is attempted that
 * exceeds the over allocation.
 */
int qtest_fault_resize_datagram(QTEST_FAULT *fault, size_t newlen);

/* Copy a BIO_MSG */
int bio_msg_copy(BIO_MSG *dst, BIO_MSG *src);

#define BIO_CTRL_NOISE_BACK_OFF       1001
#define BIO_CTRL_NOISE_RATE           1002
#define BIO_CTRL_NOISE_RECV_BANDWIDTH 1003
#define BIO_CTRL_NOISE_SEND_BANDWIDTH 1004
#define BIO_CTRL_NOISE_SET_NOW_CB     1005

struct bio_noise_now_cb_st {
    OSSL_TIME (*now_cb)(void *);
    void *now_cb_arg;
};

/* BIO filter for simulating a noisy UDP socket */
const BIO_METHOD *bio_f_noisy_dgram_filter(void);

/* Free the BIO filter method object */
void bio_f_noisy_dgram_filter_free(void);

/*
 * BIO filter for splitting QUIC datagrams containing multiple packets into
 * individual datagrams.
 */
const BIO_METHOD *bio_f_pkt_split_dgram_filter(void);

/* Free the BIO filter method object */
void bio_f_pkt_split_dgram_filter_free(void);