xref: /freebsd/crypto/openssl/fuzz/quic-server.c (revision e7be843b4a162e68651d3911f0357ed464915629)
1 /*
2  * Copyright 2025 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 
53 /*
54  * This callback validates and negotiates the desired ALPN on the server side.
55  * Accept any ALPN.
56  */
select_alpn(SSL * ssl,const unsigned char ** out,unsigned char * out_len,const unsigned char * in,unsigned int in_len,void * arg)57 static int select_alpn(SSL *ssl, const unsigned char **out,
58                        unsigned char *out_len, const unsigned char *in,
59                        unsigned int in_len, void *arg)
60 {
61     return SSL_TLSEXT_ERR_OK;
62 }
63 
FuzzerTestOneInput(const uint8_t * buf,size_t len)64 int FuzzerTestOneInput(const uint8_t *buf, size_t len)
65 {
66     SSL *server = NULL, *stream = NULL;
67     SSL *allstreams[] = {NULL, NULL, NULL, NULL};
68     size_t i, thisstream = 0, numstreams = 1;
69     BIO *in;
70     BIO *out;
71     SSL_CTX *ctx;
72     struct timeval tv;
73     int state = HANDSHAKING;
74     uint8_t tmp[1024];
75     int writelen = 0;
76 
77     if (len == 0)
78         return 0;
79 
80     ctx = SSL_CTX_new(OSSL_QUIC_server_method());
81     if (ctx == NULL)
82         goto end;
83 
84     SSL_CTX_set_alpn_select_cb(ctx, select_alpn, NULL);
85 
86     server = SSL_new_listener(ctx, 0);
87     allstreams[0] = stream = server;
88     if (server == NULL)
89         goto end;
90 
91     fake_now = ossl_ms2time(1);
92     if (!ossl_quic_set_override_now_cb(server, fake_now_cb, NULL))
93         goto end;
94 
95     in = BIO_new(BIO_s_dgram_mem());
96     if (in == NULL)
97         goto end;
98     out = BIO_new(BIO_s_dgram_mem());
99     if (out == NULL) {
100         BIO_free(in);
101         goto end;
102     }
103     if (!BIO_dgram_set_caps(out, BIO_DGRAM_CAP_HANDLES_DST_ADDR)) {
104         BIO_free(in);
105         BIO_free(out);
106         goto end;
107     }
108     SSL_set_bio(server, in, out);
109     SSL_set_accept_state(server);
110 
111     for (;;) {
112         size_t size;
113         uint64_t nxtpktms = 0;
114         OSSL_TIME nxtpkt = ossl_time_zero(), nxttimeout;
115         int isinf, ret = 0;
116 
117         if (len >= 2) {
118             if (len >= 5 && buf[0] == 0xff && buf[1] == 0xff) {
119                 switch (buf[2]) {
120                 case 0x00:
121                     if (state == READING)
122                         state = ACCEPTING_STREAM;
123                     break;
124                 case 0x01:
125                     if (state == READING)
126                         state = CREATING_STREAM;
127                     break;
128                 case 0x02:
129                     if (state == READING)
130                         state = SWAPPING_STREAM;
131                     break;
132                 default:
133                     /* ignore */
134                     break;
135                 }
136                 len -= 3;
137                 buf += 3;
138             }
139             nxtpktms = buf[0] + (buf[1] << 8);
140             nxtpkt = ossl_time_add(fake_now, ossl_ms2time(nxtpktms));
141             len -= 2;
142             buf += 2;
143         }
144 
145         for (;;) {
146             switch (state) {
147             case HANDSHAKING:
148                 ret = SSL_accept_connection(stream, 0) != NULL;
149                 if (ret == 1)
150                     state = READING;
151                 break;
152 
153             case READING:
154                 ret = SSL_read(stream, tmp, sizeof(tmp));
155                 if (ret > 0) {
156                     state = WRITING;
157                     writelen = ret;
158                     assert(writelen <= (int)sizeof(tmp));
159                 }
160                 break;
161 
162             case WRITING:
163                 ret = SSL_write(stream, tmp, writelen);
164                 if (ret > 0)
165                     state = READING;
166                 break;
167 
168             case ACCEPTING_STREAM:
169                 state = READING;
170                 ret = 1;
171                 if (numstreams == OSSL_NELEM(allstreams)
172                         || SSL_get_accept_stream_queue_len(server) == 0)
173                     break;
174                 thisstream = numstreams;
175                 stream = allstreams[numstreams++] = SSL_accept_stream(server, 0);
176                 if (stream == NULL)
177                     goto end;
178                 break;
179 
180             case CREATING_STREAM:
181                 state = READING;
182                 ret = 1;
183                 if (numstreams == OSSL_NELEM(allstreams))
184                     break;
185                 stream = SSL_new_stream(server, 0);
186                 if (stream == NULL) {
187                     /* Ignore, and go back to the previous stream */
188                     stream = allstreams[thisstream];
189                     break;
190                 }
191                 thisstream = numstreams;
192                 allstreams[numstreams++] = stream;
193                 break;
194 
195             case SWAPPING_STREAM:
196                 state = READING;
197                 ret = 1;
198                 if (numstreams == 1)
199                     break;
200                 if (++thisstream == numstreams)
201                     thisstream = 0;
202                 stream = allstreams[thisstream];
203                 break;
204             }
205             assert(stream != NULL);
206             assert(thisstream < numstreams);
207             if (ret <= 0) {
208                 switch (SSL_get_error(stream, ret)) {
209                 case SSL_ERROR_WANT_READ:
210                 case SSL_ERROR_WANT_WRITE:
211                     break;
212                 default:
213                     goto end;
214                 }
215             }
216 
217             if (!SSL_get_event_timeout(server, &tv, &isinf))
218                 goto end;
219 
220             if (isinf) {
221                 fake_now = nxtpkt;
222                 break;
223             } else {
224                 nxttimeout = ossl_time_add(fake_now,
225                                            ossl_time_from_timeval(tv));
226                 if (len > 3 && ossl_time_compare(nxttimeout, nxtpkt) >= 0) {
227                     fake_now = nxtpkt;
228                     break;
229                 }
230                 fake_now = nxttimeout;
231             }
232         }
233 
234         if (len <= 3)
235             break;
236 
237         size = buf[0] + (buf[1] << 8);
238         if (size > len - 2)
239             break;
240 
241         if (size > 0)
242             BIO_write(in, buf + 2, size);
243         len -= size + 2;
244         buf += size + 2;
245     }
246  end:
247     for (i = 0; i < numstreams; i++)
248         SSL_free(allstreams[i]);
249     ERR_clear_error();
250     SSL_CTX_free(ctx);
251 
252     return 0;
253 }
254 
FuzzerCleanup(void)255 void FuzzerCleanup(void)
256 {
257     FuzzerClearRand();
258 }
259