1 1.1 christos /* 2 1.1 christos * Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved. 3 1.1 christos * 4 1.1 christos * Licensed under the Apache License 2.0 (the "License"); 5 1.1 christos * you may not use this file except in compliance with the License. 6 1.1 christos * You may obtain a copy of the License at 7 1.1 christos * https://www.openssl.org/source/license.html 8 1.1 christos * or in the file LICENSE in the source distribution. 9 1.1 christos */ 10 1.1 christos 11 1.1 christos #include <openssl/ssl.h> 12 1.1 christos #include <openssl/err.h> 13 1.1 christos #include <openssl/bio.h> 14 1.1 christos #include "fuzzer.h" 15 1.1 christos #include "internal/sockets.h" 16 1.1 christos #include "internal/time.h" 17 1.1 christos #include "internal/quic_ssl.h" 18 1.1 christos 19 1.1 christos /* unused, to avoid warning. */ 20 1.1 christos static int idx; 21 1.1 christos 22 1.1 christos static OSSL_TIME fake_now; 23 1.1 christos 24 1.1 christos static OSSL_TIME fake_now_cb(void *arg) 25 1.1 christos { 26 1.1 christos return fake_now; 27 1.1 christos } 28 1.1 christos 29 1.1 christos int FuzzerInitialize(int *argc, char ***argv) 30 1.1 christos { 31 1.1 christos STACK_OF(SSL_COMP) *comp_methods; 32 1.1 christos 33 1.1 christos FuzzerSetRand(); 34 1.1 christos OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS | OPENSSL_INIT_ASYNC, NULL); 35 1.1 christos OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); 36 1.1 christos ERR_clear_error(); 37 1.1 christos CRYPTO_free_ex_index(0, -1); 38 1.1 christos idx = SSL_get_ex_data_X509_STORE_CTX_idx(); 39 1.1 christos comp_methods = SSL_COMP_get_compression_methods(); 40 1.1 christos if (comp_methods != NULL) 41 1.1 christos sk_SSL_COMP_sort(comp_methods); 42 1.1 christos 43 1.1 christos return 1; 44 1.1 christos } 45 1.1 christos 46 1.1.1.2 christos #define HANDSHAKING 0 47 1.1.1.2 christos #define READING 1 48 1.1.1.2 christos #define WRITING 2 49 1.1 christos #define ACCEPTING_STREAM 3 50 1.1.1.2 christos #define CREATING_STREAM 4 51 1.1.1.2 christos #define SWAPPING_STREAM 5 52 1.1 christos 53 1.1 christos int FuzzerTestOneInput(const uint8_t *buf, size_t len) 54 1.1 christos { 55 1.1 christos SSL *client = NULL, *stream = NULL; 56 1.1.1.2 christos SSL *allstreams[] = { NULL, NULL, NULL, NULL }; 57 1.1 christos size_t i, thisstream = 0, numstreams = 1; 58 1.1 christos BIO *in; 59 1.1 christos BIO *out; 60 1.1 christos SSL_CTX *ctx; 61 1.1 christos BIO_ADDR *peer_addr = NULL; 62 1.1.1.2 christos struct in_addr ina = { 0 }; 63 1.1 christos struct timeval tv; 64 1.1 christos int state = HANDSHAKING; 65 1.1 christos uint8_t tmp[1024]; 66 1.1 christos int writelen = 0; 67 1.1 christos 68 1.1 christos if (len == 0) 69 1.1 christos return 0; 70 1.1 christos 71 1.1 christos /* This only fuzzes the initial flow from the client so far. */ 72 1.1 christos ctx = SSL_CTX_new(OSSL_QUIC_client_method()); 73 1.1 christos if (ctx == NULL) 74 1.1 christos goto end; 75 1.1 christos 76 1.1 christos client = SSL_new(ctx); 77 1.1 christos if (client == NULL) 78 1.1 christos goto end; 79 1.1 christos 80 1.1 christos fake_now = ossl_ms2time(1); 81 1.1 christos if (!ossl_quic_set_override_now_cb(client, fake_now_cb, NULL)) 82 1.1 christos goto end; 83 1.1 christos 84 1.1 christos peer_addr = BIO_ADDR_new(); 85 1.1 christos if (peer_addr == NULL) 86 1.1 christos goto end; 87 1.1 christos 88 1.1 christos ina.s_addr = htonl(0x7f000001UL); 89 1.1 christos 90 1.1 christos if (!BIO_ADDR_rawmake(peer_addr, AF_INET, &ina, sizeof(ina), htons(4433))) 91 1.1.1.2 christos goto end; 92 1.1 christos 93 1.1 christos SSL_set_tlsext_host_name(client, "localhost"); 94 1.1 christos in = BIO_new(BIO_s_dgram_mem()); 95 1.1 christos if (in == NULL) 96 1.1 christos goto end; 97 1.1 christos out = BIO_new(BIO_s_dgram_mem()); 98 1.1 christos if (out == NULL) { 99 1.1 christos BIO_free(in); 100 1.1 christos goto end; 101 1.1 christos } 102 1.1 christos if (!BIO_dgram_set_caps(out, BIO_DGRAM_CAP_HANDLES_DST_ADDR)) { 103 1.1 christos BIO_free(in); 104 1.1 christos BIO_free(out); 105 1.1 christos goto end; 106 1.1 christos } 107 1.1 christos SSL_set_bio(client, in, out); 108 1.1 christos if (SSL_set_alpn_protos(client, (const unsigned char *)"\x08ossltest", 9) != 0) 109 1.1 christos goto end; 110 1.1 christos if (SSL_set1_initial_peer_addr(client, peer_addr) != 1) 111 1.1 christos goto end; 112 1.1 christos SSL_set_connect_state(client); 113 1.1 christos 114 1.1 christos if (!SSL_set_incoming_stream_policy(client, 115 1.1.1.2 christos SSL_INCOMING_STREAM_POLICY_ACCEPT, 116 1.1.1.2 christos 0)) 117 1.1 christos goto end; 118 1.1 christos 119 1.1 christos allstreams[0] = stream = client; 120 1.1 christos for (;;) { 121 1.1 christos size_t size; 122 1.1 christos uint64_t nxtpktms = 0; 123 1.1 christos OSSL_TIME nxtpkt = ossl_time_zero(), nxttimeout; 124 1.1 christos int isinf, ret = 0; 125 1.1 christos 126 1.1 christos if (len >= 2) { 127 1.1 christos if (len >= 5 && buf[0] == 0xff && buf[1] == 0xff) { 128 1.1 christos switch (buf[2]) { 129 1.1 christos case 0x00: 130 1.1 christos if (state == READING) 131 1.1 christos state = ACCEPTING_STREAM; 132 1.1 christos break; 133 1.1 christos case 0x01: 134 1.1 christos if (state == READING) 135 1.1 christos state = CREATING_STREAM; 136 1.1 christos break; 137 1.1 christos case 0x02: 138 1.1 christos if (state == READING) 139 1.1 christos state = SWAPPING_STREAM; 140 1.1 christos break; 141 1.1 christos default: 142 1.1 christos /*ignore*/ 143 1.1 christos break; 144 1.1 christos } 145 1.1 christos len -= 3; 146 1.1 christos buf += 3; 147 1.1 christos } 148 1.1 christos nxtpktms = buf[0] + (buf[1] << 8); 149 1.1 christos nxtpkt = ossl_time_add(fake_now, ossl_ms2time(nxtpktms)); 150 1.1 christos len -= 2; 151 1.1 christos buf += 2; 152 1.1 christos } 153 1.1 christos 154 1.1 christos for (;;) { 155 1.1 christos switch (state) { 156 1.1 christos case HANDSHAKING: 157 1.1 christos ret = SSL_do_handshake(stream); 158 1.1 christos if (ret == 1) 159 1.1 christos state = READING; 160 1.1 christos break; 161 1.1 christos 162 1.1 christos case READING: 163 1.1 christos ret = SSL_read(stream, tmp, sizeof(tmp)); 164 1.1 christos if (ret > 0) { 165 1.1 christos state = WRITING; 166 1.1 christos writelen = ret; 167 1.1 christos assert(writelen <= (int)sizeof(tmp)); 168 1.1 christos } 169 1.1 christos break; 170 1.1 christos 171 1.1 christos case WRITING: 172 1.1 christos ret = SSL_write(stream, tmp, writelen); 173 1.1 christos if (ret > 0) 174 1.1 christos state = READING; 175 1.1 christos break; 176 1.1 christos 177 1.1 christos case ACCEPTING_STREAM: 178 1.1 christos state = READING; 179 1.1 christos ret = 1; 180 1.1 christos if (numstreams == OSSL_NELEM(allstreams) 181 1.1.1.2 christos || SSL_get_accept_stream_queue_len(client) == 0) 182 1.1 christos break; 183 1.1 christos thisstream = numstreams; 184 1.1 christos stream = allstreams[numstreams++] 185 1.1.1.2 christos = SSL_accept_stream(client, 0); 186 1.1 christos if (stream == NULL) 187 1.1 christos goto end; 188 1.1 christos break; 189 1.1 christos 190 1.1 christos case CREATING_STREAM: 191 1.1 christos state = READING; 192 1.1 christos ret = 1; 193 1.1 christos if (numstreams == OSSL_NELEM(allstreams)) 194 1.1 christos break; 195 1.1 christos stream = SSL_new_stream(client, 0); 196 1.1 christos if (stream == NULL) { 197 1.1 christos /* Ignore, and go back to the previous stream */ 198 1.1 christos stream = allstreams[thisstream]; 199 1.1 christos break; 200 1.1 christos } 201 1.1 christos thisstream = numstreams; 202 1.1 christos allstreams[numstreams++] = stream; 203 1.1 christos break; 204 1.1 christos 205 1.1 christos case SWAPPING_STREAM: 206 1.1 christos state = READING; 207 1.1 christos ret = 1; 208 1.1 christos if (numstreams == 1) 209 1.1 christos break; 210 1.1 christos if (++thisstream == numstreams) 211 1.1 christos thisstream = 0; 212 1.1 christos stream = allstreams[thisstream]; 213 1.1 christos break; 214 1.1 christos } 215 1.1 christos assert(stream != NULL); 216 1.1 christos assert(thisstream < numstreams); 217 1.1 christos if (ret <= 0) { 218 1.1 christos switch (SSL_get_error(stream, ret)) { 219 1.1 christos case SSL_ERROR_WANT_READ: 220 1.1 christos case SSL_ERROR_WANT_WRITE: 221 1.1 christos break; 222 1.1 christos default: 223 1.1 christos goto end; 224 1.1 christos } 225 1.1 christos } 226 1.1 christos 227 1.1 christos if (!SSL_get_event_timeout(client, &tv, &isinf)) 228 1.1 christos goto end; 229 1.1 christos 230 1.1 christos if (isinf) { 231 1.1 christos fake_now = nxtpkt; 232 1.1 christos break; 233 1.1 christos } else { 234 1.1 christos nxttimeout = ossl_time_add(fake_now, 235 1.1.1.2 christos ossl_time_from_timeval(tv)); 236 1.1 christos if (len > 3 && ossl_time_compare(nxttimeout, nxtpkt) >= 0) { 237 1.1 christos fake_now = nxtpkt; 238 1.1 christos break; 239 1.1 christos } 240 1.1 christos fake_now = nxttimeout; 241 1.1 christos } 242 1.1 christos } 243 1.1 christos 244 1.1 christos if (len <= 3) 245 1.1 christos break; 246 1.1 christos 247 1.1 christos size = buf[0] + (buf[1] << 8); 248 1.1 christos if (size > len - 2) 249 1.1 christos break; 250 1.1 christos 251 1.1 christos if (size > 0) 252 1.1.1.2 christos BIO_write(in, buf + 2, size); 253 1.1 christos len -= size + 2; 254 1.1 christos buf += size + 2; 255 1.1 christos } 256 1.1.1.2 christos end: 257 1.1 christos for (i = 0; i < numstreams; i++) 258 1.1 christos SSL_free(allstreams[i]); 259 1.1 christos ERR_clear_error(); 260 1.1 christos SSL_CTX_free(ctx); 261 1.1 christos BIO_ADDR_free(peer_addr); 262 1.1 christos 263 1.1 christos return 0; 264 1.1 christos } 265 1.1 christos 266 1.1 christos void FuzzerCleanup(void) 267 1.1 christos { 268 1.1 christos FuzzerClearRand(); 269 1.1 christos } 270