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