Coverage Report

Created: 2026-10-28 06:28

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