xref: /openssl/fuzz/quic-client.c (revision 3fa274ca)
1 /*
2  * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * https://www.openssl.org/source/license.html
8  * or in the file LICENSE in the source distribution.
9  */
10 
11 #include <openssl/ssl.h>
12 #include <openssl/err.h>
13 #include <openssl/bio.h>
14 #include "fuzzer.h"
15 #include "internal/sockets.h"
16 #include "internal/time.h"
17 #include "internal/quic_ssl.h"
18 
19 /* unused, to avoid warning. */
20 static int idx;
21 
22 static OSSL_TIME fake_now;
23 
fake_now_cb(void * arg)24 static OSSL_TIME fake_now_cb(void *arg)
25 {
26     return fake_now;
27 }
28 
FuzzerInitialize(int * argc,char *** argv)29 int FuzzerInitialize(int *argc, char ***argv)
30 {
31     STACK_OF(SSL_COMP) *comp_methods;
32 
33     FuzzerSetRand();
34     OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS | OPENSSL_INIT_ASYNC, NULL);
35     OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
36     ERR_clear_error();
37     CRYPTO_free_ex_index(0, -1);
38     idx = SSL_get_ex_data_X509_STORE_CTX_idx();
39     comp_methods = SSL_COMP_get_compression_methods();
40     if (comp_methods != NULL)
41         sk_SSL_COMP_sort(comp_methods);
42 
43     return 1;
44 }
45 
46 #define HANDSHAKING      0
47 #define READING          1
48 #define WRITING          2
49 #define ACCEPTING_STREAM 3
50 #define CREATING_STREAM  4
51 #define SWAPPING_STREAM  5
52 
FuzzerTestOneInput(const uint8_t * buf,size_t len)53 int FuzzerTestOneInput(const uint8_t *buf, size_t len)
54 {
55     SSL *client = NULL, *stream = NULL;
56     SSL *allstreams[] = {NULL, NULL, NULL, NULL};
57     size_t i, thisstream = 0, numstreams = 1;
58     BIO *in;
59     BIO *out;
60     SSL_CTX *ctx;
61     BIO_ADDR *peer_addr = NULL;
62     struct in_addr ina = {0};
63     struct timeval tv;
64     int state = HANDSHAKING;
65     uint8_t tmp[1024];
66     int writelen = 0;
67 
68     if (len == 0)
69         return 0;
70 
71     /* This only fuzzes the initial flow from the client so far. */
72     ctx = SSL_CTX_new(OSSL_QUIC_client_method());
73     if (ctx == NULL)
74         goto end;
75 
76     client = SSL_new(ctx);
77     if (client == NULL)
78         goto end;
79 
80     fake_now = ossl_ms2time(1);
81     if (!ossl_quic_conn_set_override_now_cb(client, fake_now_cb, NULL))
82         goto end;
83 
84     peer_addr = BIO_ADDR_new();
85     if (peer_addr == NULL)
86         goto end;
87 
88     ina.s_addr = htonl(0x7f000001UL);
89 
90     if (!BIO_ADDR_rawmake(peer_addr, AF_INET, &ina, sizeof(ina), htons(4433)))
91        goto end;
92 
93     SSL_set_tlsext_host_name(client, "localhost");
94     in = BIO_new(BIO_s_dgram_mem());
95     if (in == NULL)
96         goto end;
97     out = BIO_new(BIO_s_dgram_mem());
98     if (out == NULL) {
99         BIO_free(in);
100         goto end;
101     }
102     if (!BIO_dgram_set_caps(out, BIO_DGRAM_CAP_HANDLES_DST_ADDR)) {
103         BIO_free(in);
104         BIO_free(out);
105         goto end;
106     }
107     SSL_set_bio(client, in, out);
108     if (SSL_set_alpn_protos(client, (const unsigned char *)"\x08ossltest", 9) != 0)
109         goto end;
110     if (SSL_set1_initial_peer_addr(client, peer_addr) != 1)
111         goto end;
112     SSL_set_connect_state(client);
113 
114     if (!SSL_set_incoming_stream_policy(client,
115                                         SSL_INCOMING_STREAM_POLICY_ACCEPT,
116                                         0))
117         goto end;
118 
119     allstreams[0] = stream = client;
120     for (;;) {
121         size_t size;
122         uint64_t nxtpktms = 0;
123         OSSL_TIME nxtpkt = ossl_time_zero(), nxttimeout;
124         int isinf, ret = 0;
125 
126         if (len >= 2) {
127             if (len >= 5 && buf[0] == 0xff && buf[1] == 0xff) {
128                 switch (buf[2]) {
129                 case 0x00:
130                     if (state == READING)
131                         state = ACCEPTING_STREAM;
132                     break;
133                 case 0x01:
134                     if (state == READING)
135                         state = CREATING_STREAM;
136                     break;
137                 case 0x02:
138                     if (state == READING)
139                         state = SWAPPING_STREAM;
140                     break;
141                 default:
142                     /*ignore*/
143                     break;
144                 }
145                 len -= 3;
146                 buf += 3;
147             }
148             nxtpktms = buf[0] + (buf[1] << 8);
149             nxtpkt = ossl_time_add(fake_now, ossl_ms2time(nxtpktms));
150             len -= 2;
151             buf += 2;
152         }
153 
154         for (;;) {
155             switch (state) {
156             case HANDSHAKING:
157                 ret = SSL_do_handshake(stream);
158                 if (ret == 1)
159                     state = READING;
160                 break;
161 
162             case READING:
163                 ret = SSL_read(stream, tmp, sizeof(tmp));
164                 if (ret > 0) {
165                     state = WRITING;
166                     writelen = ret;
167                     assert(writelen <= (int)sizeof(tmp));
168                 }
169                 break;
170 
171             case WRITING:
172                 ret = SSL_write(stream, tmp, writelen);
173                 if (ret > 0)
174                     state = READING;
175                 break;
176 
177             case ACCEPTING_STREAM:
178                 state = READING;
179                 ret = 1;
180                 if (numstreams == OSSL_NELEM(allstreams)
181                         || SSL_get_accept_stream_queue_len(client) == 0)
182                     break;
183                 thisstream = numstreams;
184                 stream = allstreams[numstreams++]
185                         = SSL_accept_stream(client, 0);
186                 if (stream == NULL)
187                     goto end;
188                 break;
189 
190             case CREATING_STREAM:
191                 state = READING;
192                 ret = 1;
193                 if (numstreams == OSSL_NELEM(allstreams))
194                     break;
195                 stream = SSL_new_stream(client, 0);
196                 if (stream == NULL) {
197                     /* Ignore, and go back to the previous stream */
198                     stream = allstreams[thisstream];
199                     break;
200                 }
201                 thisstream = numstreams;
202                 allstreams[numstreams++] = stream;
203                 break;
204 
205             case SWAPPING_STREAM:
206                 state = READING;
207                 ret = 1;
208                 if (numstreams == 1)
209                     break;
210                 if (++thisstream == numstreams)
211                     thisstream = 0;
212                 stream = allstreams[thisstream];
213                 break;
214             }
215             assert(stream != NULL);
216             assert(thisstream < numstreams);
217             if (ret <= 0) {
218                 switch (SSL_get_error(stream, ret)) {
219                 case SSL_ERROR_WANT_READ:
220                 case SSL_ERROR_WANT_WRITE:
221                     break;
222                 default:
223                     goto end;
224                 }
225             }
226 
227             if (!SSL_get_event_timeout(client, &tv, &isinf))
228                 goto end;
229 
230             if (isinf) {
231                 fake_now = nxtpkt;
232                 break;
233             } else {
234                 nxttimeout = ossl_time_add(fake_now,
235                                            ossl_time_from_timeval(tv));
236                 if (len > 3 && ossl_time_compare(nxttimeout, nxtpkt) >= 0) {
237                     fake_now = nxtpkt;
238                     break;
239                 }
240                 fake_now = nxttimeout;
241             }
242         }
243 
244         if (len <= 3)
245             break;
246 
247         size = buf[0] + (buf[1] << 8);
248         if (size > len - 2)
249             break;
250 
251         if (size > 0)
252             BIO_write(in, buf+2, size);
253         len -= size + 2;
254         buf += size + 2;
255     }
256  end:
257     for (i = 0; i < numstreams; i++)
258         SSL_free(allstreams[i]);
259     ERR_clear_error();
260     SSL_CTX_free(ctx);
261     BIO_ADDR_free(peer_addr);
262 
263     return 0;
264 }
265 
FuzzerCleanup(void)266 void FuzzerCleanup(void)
267 {
268     FuzzerClearRand();
269 }
270