Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/fuzz/quic-server.c
34859 views
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
24
static OSSL_TIME fake_now_cb(void *arg)
25
{
26
return fake_now;
27
}
28
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
*/
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
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
255
void FuzzerCleanup(void)
256
{
257
FuzzerClearRand();
258
}
259
260