2dc2b3c9b2c88b7a97e8e056152eba18812474fc
[openssl.git] / fuzz / quic-client.c
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
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 int FuzzerTestOneInput(const uint8_t *buf, size_t len)
47 {
48     SSL *client = NULL;
49     BIO *in;
50     BIO *out;
51     SSL_CTX *ctx;
52     BIO_ADDR *peer_addr = NULL;
53     struct in_addr ina = {0};
54     struct timeval tv;
55
56     if (len == 0)
57         return 0;
58
59     /* This only fuzzes the initial flow from the client so far. */
60     ctx = SSL_CTX_new(OSSL_QUIC_client_method());
61     if (ctx == NULL)
62         goto end;
63
64     client = SSL_new(ctx);
65     if (client == NULL)
66         goto end;
67
68     fake_now = ossl_ms2time(1);
69     if (!ossl_quic_conn_set_override_now_cb(client, fake_now_cb, NULL))
70         goto end;
71
72     peer_addr = BIO_ADDR_new();
73     if (peer_addr == NULL)
74         goto end;
75
76     ina.s_addr = htonl(0x7f000001UL);
77
78     if (!BIO_ADDR_rawmake(peer_addr, AF_INET, &ina, sizeof(ina), htons(4433)))
79        goto end;
80
81     SSL_set_tlsext_host_name(client, "localhost");
82     in = BIO_new(BIO_s_dgram_mem());
83     if (in == NULL)
84         goto end;
85     out = BIO_new(BIO_s_dgram_mem());
86     if (out == NULL) {
87         BIO_free(in);
88         goto end;
89     }
90     if (!BIO_dgram_set_caps(out, BIO_DGRAM_CAP_HANDLES_DST_ADDR)) {
91         BIO_free(in);
92         BIO_free(out);
93         goto end;
94     }
95     SSL_set_bio(client, in, out);
96     if (SSL_set_alpn_protos(client, (const unsigned char *)"\x08ossltest", 9) != 0)
97         goto end;
98     if (SSL_set1_initial_peer_addr(client, peer_addr) != 1)
99         goto end;
100     SSL_set_connect_state(client);
101
102     for (;;) {
103         size_t size;
104         uint64_t nxtpktms = 0;
105         OSSL_TIME nxtpkt = ossl_time_zero(), nxttimeout;
106         int isinf, ret;
107
108         if (len >= 2) {
109             nxtpktms = buf[0] + (buf[1] << 8);
110             nxtpkt = ossl_time_add(fake_now, ossl_ms2time(nxtpktms));
111             len -= 2;
112             buf += 2;
113         }
114
115         for (;;) {
116             if ((ret = SSL_do_handshake(client)) == 1) {
117                 /*
118                 * Keep reading application data until there are no more
119                 * datagrams to inject or a fatal error occurs
120                 */
121                 uint8_t tmp[1024];
122
123                 ret = SSL_read(client, tmp, sizeof(tmp));
124             }
125             if (ret <= 0) {
126                 switch (SSL_get_error(client, ret)) {
127                 case SSL_ERROR_WANT_READ:
128                 case SSL_ERROR_WANT_WRITE:
129                     break;
130                 default:
131                     goto end;
132                 }
133             }
134
135             if (!SSL_get_event_timeout(client, &tv, &isinf))
136                 goto end;
137
138             if (isinf) {
139                 fake_now = nxtpkt;
140                 break;
141             } else {
142                 nxttimeout = ossl_time_add(fake_now,
143                                            ossl_time_from_timeval(tv));
144                 if (len > 3 && ossl_time_compare(nxttimeout, nxtpkt) >= 0) {
145                     fake_now = nxtpkt;
146                     break;
147                 }
148                 fake_now = nxttimeout;
149             }
150         }
151
152         if (len <= 3)
153             break;
154
155         size = buf[0] + (buf[1] << 8);
156         if (size > len - 2)
157             break;
158
159         if (size > 0)
160             BIO_write(in, buf+2, size);
161         len -= size + 2;
162         buf += size + 2;
163     }
164  end:
165     SSL_free(client);
166     ERR_clear_error();
167     SSL_CTX_free(ctx);
168     BIO_ADDR_free(peer_addr);
169
170     return 0;
171 }
172
173 void FuzzerCleanup(void)
174 {
175     FuzzerClearRand();
176 }