Path: blob/main/crypto/openssl/fuzz/quic-client.c
104874 views
/*1* Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License");4* you may not use this file except in compliance with the License.5* You may obtain a copy of the License at6* https://www.openssl.org/source/license.html7* or in the file LICENSE in the source distribution.8*/910#include <openssl/ssl.h>11#include <openssl/err.h>12#include <openssl/bio.h>13#include "fuzzer.h"14#include "internal/sockets.h"15#include "internal/time.h"16#include "internal/quic_ssl.h"1718/* unused, to avoid warning. */19static int idx;2021static OSSL_TIME fake_now;2223static OSSL_TIME fake_now_cb(void *arg)24{25return fake_now;26}2728int FuzzerInitialize(int *argc, char ***argv)29{30STACK_OF(SSL_COMP) *comp_methods;3132FuzzerSetRand();33OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS | OPENSSL_INIT_ASYNC, NULL);34OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);35ERR_clear_error();36CRYPTO_free_ex_index(0, -1);37idx = SSL_get_ex_data_X509_STORE_CTX_idx();38comp_methods = SSL_COMP_get_compression_methods();39if (comp_methods != NULL)40sk_SSL_COMP_sort(comp_methods);4142return 1;43}4445#define HANDSHAKING 046#define READING 147#define WRITING 248#define ACCEPTING_STREAM 349#define CREATING_STREAM 450#define SWAPPING_STREAM 55152int FuzzerTestOneInput(const uint8_t *buf, size_t len)53{54SSL *client = NULL, *stream = NULL;55SSL *allstreams[] = { NULL, NULL, NULL, NULL };56size_t i, thisstream = 0, numstreams = 1;57BIO *in;58BIO *out;59SSL_CTX *ctx;60BIO_ADDR *peer_addr = NULL;61struct in_addr ina = { 0 };62struct timeval tv;63int state = HANDSHAKING;64uint8_t tmp[1024];65int writelen = 0;6667if (len == 0)68return 0;6970/* This only fuzzes the initial flow from the client so far. */71ctx = SSL_CTX_new(OSSL_QUIC_client_method());72if (ctx == NULL)73goto end;7475client = SSL_new(ctx);76if (client == NULL)77goto end;7879fake_now = ossl_ms2time(1);80if (!ossl_quic_set_override_now_cb(client, fake_now_cb, NULL))81goto end;8283peer_addr = BIO_ADDR_new();84if (peer_addr == NULL)85goto end;8687ina.s_addr = htonl(0x7f000001UL);8889if (!BIO_ADDR_rawmake(peer_addr, AF_INET, &ina, sizeof(ina), htons(4433)))90goto end;9192SSL_set_tlsext_host_name(client, "localhost");93in = BIO_new(BIO_s_dgram_mem());94if (in == NULL)95goto end;96out = BIO_new(BIO_s_dgram_mem());97if (out == NULL) {98BIO_free(in);99goto end;100}101if (!BIO_dgram_set_caps(out, BIO_DGRAM_CAP_HANDLES_DST_ADDR)) {102BIO_free(in);103BIO_free(out);104goto end;105}106SSL_set_bio(client, in, out);107if (SSL_set_alpn_protos(client, (const unsigned char *)"\x08ossltest", 9) != 0)108goto end;109if (SSL_set1_initial_peer_addr(client, peer_addr) != 1)110goto end;111SSL_set_connect_state(client);112113if (!SSL_set_incoming_stream_policy(client,114SSL_INCOMING_STREAM_POLICY_ACCEPT,1150))116goto end;117118allstreams[0] = stream = client;119for (;;) {120size_t size;121uint64_t nxtpktms = 0;122OSSL_TIME nxtpkt = ossl_time_zero(), nxttimeout;123int isinf, ret = 0;124125if (len >= 2) {126if (len >= 5 && buf[0] == 0xff && buf[1] == 0xff) {127switch (buf[2]) {128case 0x00:129if (state == READING)130state = ACCEPTING_STREAM;131break;132case 0x01:133if (state == READING)134state = CREATING_STREAM;135break;136case 0x02:137if (state == READING)138state = SWAPPING_STREAM;139break;140default:141/*ignore*/142break;143}144len -= 3;145buf += 3;146}147nxtpktms = buf[0] + (buf[1] << 8);148nxtpkt = ossl_time_add(fake_now, ossl_ms2time(nxtpktms));149len -= 2;150buf += 2;151}152153for (;;) {154switch (state) {155case HANDSHAKING:156ret = SSL_do_handshake(stream);157if (ret == 1)158state = READING;159break;160161case READING:162ret = SSL_read(stream, tmp, sizeof(tmp));163if (ret > 0) {164state = WRITING;165writelen = ret;166assert(writelen <= (int)sizeof(tmp));167}168break;169170case WRITING:171ret = SSL_write(stream, tmp, writelen);172if (ret > 0)173state = READING;174break;175176case ACCEPTING_STREAM:177state = READING;178ret = 1;179if (numstreams == OSSL_NELEM(allstreams)180|| SSL_get_accept_stream_queue_len(client) == 0)181break;182thisstream = numstreams;183stream = allstreams[numstreams++]184= SSL_accept_stream(client, 0);185if (stream == NULL)186goto end;187break;188189case CREATING_STREAM:190state = READING;191ret = 1;192if (numstreams == OSSL_NELEM(allstreams))193break;194stream = SSL_new_stream(client, 0);195if (stream == NULL) {196/* Ignore, and go back to the previous stream */197stream = allstreams[thisstream];198break;199}200thisstream = numstreams;201allstreams[numstreams++] = stream;202break;203204case SWAPPING_STREAM:205state = READING;206ret = 1;207if (numstreams == 1)208break;209if (++thisstream == numstreams)210thisstream = 0;211stream = allstreams[thisstream];212break;213}214assert(stream != NULL);215assert(thisstream < numstreams);216if (ret <= 0) {217switch (SSL_get_error(stream, ret)) {218case SSL_ERROR_WANT_READ:219case SSL_ERROR_WANT_WRITE:220break;221default:222goto end;223}224}225226if (!SSL_get_event_timeout(client, &tv, &isinf))227goto end;228229if (isinf) {230fake_now = nxtpkt;231break;232} else {233nxttimeout = ossl_time_add(fake_now,234ossl_time_from_timeval(tv));235if (len > 3 && ossl_time_compare(nxttimeout, nxtpkt) >= 0) {236fake_now = nxtpkt;237break;238}239fake_now = nxttimeout;240}241}242243if (len <= 3)244break;245246size = buf[0] + (buf[1] << 8);247if (size > len - 2)248break;249250if (size > 0)251BIO_write(in, buf + 2, size);252len -= size + 2;253buf += size + 2;254}255end:256for (i = 0; i < numstreams; i++)257SSL_free(allstreams[i]);258ERR_clear_error();259SSL_CTX_free(ctx);260BIO_ADDR_free(peer_addr);261262return 0;263}264265void FuzzerCleanup(void)266{267FuzzerClearRand();268}269270271