Coverage Report

Created: 2026-09-12 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl41/fuzz/quic-client.c
Line
Count
Source
1
/*
2
 * Copyright 2016-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
/* 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
175M
{
26
175M
    return fake_now;
27
175M
}
28
29
int FuzzerInitialize(int *argc, char ***argv)
30
64
{
31
64
    STACK_OF(SSL_COMP) *comp_methods;
32
33
64
    FuzzerSetRand();
34
64
    OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS | OPENSSL_INIT_ASYNC, NULL);
35
64
    OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
36
64
    ERR_clear_error();
37
64
    CRYPTO_free_ex_index(0, -1);
38
64
    idx = SSL_get_ex_data_X509_STORE_CTX_idx();
39
64
    comp_methods = SSL_COMP_get_compression_methods();
40
64
    if (comp_methods != NULL)
41
64
        sk_SSL_COMP_sort(comp_methods);
42
43
64
    return 1;
44
64
}
45
46
2.13M
#define HANDSHAKING 0
47
6.91M
#define READING 1
48
3.54k
#define WRITING 2
49
1.55M
#define ACCEPTING_STREAM 3
50
838k
#define CREATING_STREAM 4
51
2.48k
#define SWAPPING_STREAM 5
52
53
int FuzzerTestOneInput(const uint8_t *buf, size_t len)
54
8.47k
{
55
8.47k
    SSL *client = NULL, *stream = NULL;
56
8.47k
    SSL *allstreams[] = { NULL, NULL, NULL, NULL };
57
8.47k
    size_t i, thisstream = 0, numstreams = 1;
58
8.47k
    BIO *in;
59
8.47k
    BIO *out;
60
8.47k
    SSL_CTX *ctx;
61
8.47k
    BIO_ADDR *peer_addr = NULL;
62
8.47k
    struct in_addr ina = { 0 };
63
8.47k
    struct timeval tv;
64
8.47k
    int state = HANDSHAKING;
65
8.47k
    uint8_t tmp[1024];
66
8.47k
    int writelen = 0;
67
68
8.47k
    if (len == 0)
69
0
        return 0;
70
71
    /* This only fuzzes the initial flow from the client so far. */
72
8.47k
    ctx = SSL_CTX_new(OSSL_QUIC_client_method());
73
8.47k
    if (ctx == NULL)
74
0
        goto end;
75
76
8.47k
    client = SSL_new(ctx);
77
8.47k
    if (client == NULL)
78
0
        goto end;
79
80
8.47k
    allstreams[0] = stream = client;
81
82
8.47k
    fake_now = ossl_ms2time(1);
83
8.47k
    if (!ossl_quic_set_override_now_cb(client, fake_now_cb, NULL))
84
0
        goto end;
85
86
8.47k
    peer_addr = BIO_ADDR_new();
87
8.47k
    if (peer_addr == NULL)
88
0
        goto end;
89
90
8.47k
    ina.s_addr = htonl(0x7f000001UL);
91
92
8.47k
    if (!BIO_ADDR_rawmake(peer_addr, AF_INET, &ina, sizeof(ina), htons(4433)))
93
0
        goto end;
94
95
8.47k
    if (SSL_set_tlsext_host_name(client, "localhost") != 1)
96
0
        goto end;
97
8.47k
    in = BIO_new(BIO_s_dgram_mem());
98
8.47k
    if (in == NULL)
99
0
        goto end;
100
8.47k
    out = BIO_new(BIO_s_dgram_mem());
101
8.47k
    if (out == NULL) {
102
0
        BIO_free(in);
103
0
        goto end;
104
0
    }
105
8.47k
    if (!BIO_dgram_set_caps(out, BIO_DGRAM_CAP_HANDLES_DST_ADDR)) {
106
0
        BIO_free(in);
107
0
        BIO_free(out);
108
0
        goto end;
109
0
    }
110
8.47k
    SSL_set_bio(client, in, out);
111
8.47k
    if (SSL_set_alpn_protos(client, (const unsigned char *)"\x08ossltest", 9) != 0)
112
0
        goto end;
113
8.47k
    if (SSL_set1_initial_peer_addr(client, peer_addr) != 1)
114
0
        goto end;
115
8.47k
    SSL_set_connect_state(client);
116
117
8.47k
    if (!SSL_set_incoming_stream_policy(client,
118
8.47k
            SSL_INCOMING_STREAM_POLICY_ACCEPT,
119
8.47k
            0))
120
0
        goto end;
121
122
5.09M
    for (;;) {
123
5.09M
        size_t size;
124
5.09M
        uint64_t nxtpktms = 0;
125
5.09M
        OSSL_TIME nxtpkt = ossl_time_zero(), nxttimeout;
126
5.09M
        int isinf, ret = 0;
127
128
5.09M
        if (len >= 2) {
129
5.09M
            if (len >= 5 && buf[0] == 0xff && buf[1] == 0xff) {
130
1.23M
                switch (buf[2]) {
131
798k
                case 0x00:
132
798k
                    if (state == READING)
133
779k
                        state = ACCEPTING_STREAM;
134
798k
                    break;
135
430k
                case 0x01:
136
430k
                    if (state == READING)
137
419k
                        state = CREATING_STREAM;
138
430k
                    break;
139
1.45k
                case 0x02:
140
1.45k
                    if (state == READING)
141
1.24k
                        state = SWAPPING_STREAM;
142
1.45k
                    break;
143
1.27k
                default:
144
                    /*ignore*/
145
1.27k
                    break;
146
1.23M
                }
147
1.23M
                len -= 3;
148
1.23M
                buf += 3;
149
1.23M
            }
150
5.09M
            nxtpktms = buf[0] + (buf[1] << 8);
151
5.09M
            nxtpkt = ossl_time_add(fake_now, ossl_ms2time(nxtpktms));
152
5.09M
            len -= 2;
153
5.09M
            buf += 2;
154
5.09M
        }
155
156
7.80M
        for (;;) {
157
7.80M
            switch (state) {
158
2.12M
            case HANDSHAKING:
159
2.12M
                ret = SSL_do_handshake(stream);
160
2.12M
                if (ret == 1)
161
2.18k
                    state = READING;
162
2.12M
                break;
163
164
4.47M
            case READING:
165
4.47M
                ret = SSL_read(stream, tmp, sizeof(tmp));
166
4.47M
                if (ret > 0) {
167
719
                    state = WRITING;
168
719
                    writelen = ret;
169
719
                    assert(writelen <= (int)sizeof(tmp));
170
719
                }
171
4.47M
                break;
172
173
4.47M
            case WRITING:
174
2.82k
                ret = SSL_write(stream, tmp, writelen);
175
2.82k
                if (ret > 0)
176
576
                    state = READING;
177
2.82k
                break;
178
179
779k
            case ACCEPTING_STREAM:
180
779k
                state = READING;
181
779k
                ret = 1;
182
779k
                if (numstreams == OSSL_NELEM(allstreams)
183
2.13k
                    || SSL_get_accept_stream_queue_len(client) == 0)
184
779k
                    break;
185
145
                thisstream = numstreams;
186
145
                stream = allstreams[numstreams++]
187
145
                    = SSL_accept_stream(client, 0);
188
145
                if (stream == NULL)
189
0
                    goto end;
190
145
                break;
191
192
419k
            case CREATING_STREAM:
193
419k
                state = READING;
194
419k
                ret = 1;
195
419k
                if (numstreams == OSSL_NELEM(allstreams))
196
416k
                    break;
197
2.40k
                stream = SSL_new_stream(client, 0);
198
2.40k
                if (stream == NULL) {
199
                    /* Ignore, and go back to the previous stream */
200
1.56k
                    stream = allstreams[thisstream];
201
1.56k
                    break;
202
1.56k
                }
203
839
                thisstream = numstreams;
204
839
                allstreams[numstreams++] = stream;
205
839
                break;
206
207
1.24k
            case SWAPPING_STREAM:
208
1.24k
                state = READING;
209
1.24k
                ret = 1;
210
1.24k
                if (numstreams == 1)
211
207
                    break;
212
1.03k
                if (++thisstream == numstreams)
213
347
                    thisstream = 0;
214
1.03k
                stream = allstreams[thisstream];
215
1.03k
                break;
216
7.80M
            }
217
7.80M
            assert(stream != NULL);
218
7.80M
            assert(thisstream < numstreams);
219
7.80M
            if (ret <= 0) {
220
6.60M
                switch (SSL_get_error(stream, ret)) {
221
6.59M
                case SSL_ERROR_WANT_READ:
222
6.59M
                case SSL_ERROR_WANT_WRITE:
223
6.59M
                    break;
224
6.94k
                default:
225
6.94k
                    goto end;
226
6.60M
                }
227
6.60M
            }
228
229
7.80M
            if (!SSL_get_event_timeout(client, &tv, &isinf))
230
0
                goto end;
231
232
7.80M
            if (isinf) {
233
5.11k
                fake_now = nxtpkt;
234
5.11k
                break;
235
7.79M
            } else {
236
7.79M
                nxttimeout = ossl_time_add(fake_now,
237
7.79M
                    ossl_time_from_timeval(tv));
238
7.79M
                if (len > 3 && ossl_time_compare(nxttimeout, nxtpkt) >= 0) {
239
5.08M
                    fake_now = nxtpkt;
240
5.08M
                    break;
241
5.08M
                }
242
2.71M
                fake_now = nxttimeout;
243
2.71M
            }
244
7.80M
        }
245
246
5.09M
        if (len <= 3)
247
340
            break;
248
249
5.09M
        size = buf[0] + (buf[1] << 8);
250
5.09M
        if (size > len - 2)
251
1.18k
            break;
252
253
5.09M
        if (size > 0)
254
1.92M
            BIO_write(in, buf + 2, (int)size);
255
5.09M
        len -= size + 2;
256
5.09M
        buf += size + 2;
257
5.09M
    }
258
8.47k
end:
259
17.9k
    for (i = 0; i < numstreams; i++)
260
9.45k
        SSL_free(allstreams[i]);
261
8.47k
    ERR_clear_error();
262
8.47k
    SSL_CTX_free(ctx);
263
8.47k
    BIO_ADDR_free(peer_addr);
264
265
8.47k
    return 0;
266
8.47k
}
267
268
void FuzzerCleanup(void)
269
0
{
270
0
    FuzzerClearRand();
271
0
}