123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- /*
- * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
- *
- * Licensed under the Apache License 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * https://www.openssl.org/source/license.html
- * or in the file LICENSE in the source distribution.
- */
- #include <openssl/ssl.h>
- #include <openssl/err.h>
- #include <openssl/bio.h>
- #include "fuzzer.h"
- #include "internal/sockets.h"
- #include "internal/time.h"
- #include "internal/quic_ssl.h"
- /* unused, to avoid warning. */
- static int idx;
- static OSSL_TIME fake_now;
- static OSSL_TIME fake_now_cb(void *arg)
- {
- return fake_now;
- }
- int FuzzerInitialize(int *argc, char ***argv)
- {
- STACK_OF(SSL_COMP) *comp_methods;
- FuzzerSetRand();
- OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS | OPENSSL_INIT_ASYNC, NULL);
- OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
- ERR_clear_error();
- CRYPTO_free_ex_index(0, -1);
- idx = SSL_get_ex_data_X509_STORE_CTX_idx();
- comp_methods = SSL_COMP_get_compression_methods();
- if (comp_methods != NULL)
- sk_SSL_COMP_sort(comp_methods);
- return 1;
- }
- #define HANDSHAKING 0
- #define READING 1
- #define WRITING 2
- #define ACCEPTING_STREAM 3
- #define CREATING_STREAM 4
- #define SWAPPING_STREAM 5
- int FuzzerTestOneInput(const uint8_t *buf, size_t len)
- {
- SSL *client = NULL, *stream = NULL;
- SSL *allstreams[] = {NULL, NULL, NULL, NULL};
- size_t i, thisstream = 0, numstreams = 1;
- BIO *in;
- BIO *out;
- SSL_CTX *ctx;
- BIO_ADDR *peer_addr = NULL;
- struct in_addr ina = {0};
- struct timeval tv;
- int state = HANDSHAKING;
- uint8_t tmp[1024];
- int writelen = 0;
- if (len == 0)
- return 0;
- /* This only fuzzes the initial flow from the client so far. */
- ctx = SSL_CTX_new(OSSL_QUIC_client_method());
- if (ctx == NULL)
- goto end;
- client = SSL_new(ctx);
- if (client == NULL)
- goto end;
- fake_now = ossl_ms2time(1);
- if (!ossl_quic_conn_set_override_now_cb(client, fake_now_cb, NULL))
- goto end;
- peer_addr = BIO_ADDR_new();
- if (peer_addr == NULL)
- goto end;
- ina.s_addr = htonl(0x7f000001UL);
- if (!BIO_ADDR_rawmake(peer_addr, AF_INET, &ina, sizeof(ina), htons(4433)))
- goto end;
- SSL_set_tlsext_host_name(client, "localhost");
- in = BIO_new(BIO_s_dgram_mem());
- if (in == NULL)
- goto end;
- out = BIO_new(BIO_s_dgram_mem());
- if (out == NULL) {
- BIO_free(in);
- goto end;
- }
- if (!BIO_dgram_set_caps(out, BIO_DGRAM_CAP_HANDLES_DST_ADDR)) {
- BIO_free(in);
- BIO_free(out);
- goto end;
- }
- SSL_set_bio(client, in, out);
- if (SSL_set_alpn_protos(client, (const unsigned char *)"\x08ossltest", 9) != 0)
- goto end;
- if (SSL_set1_initial_peer_addr(client, peer_addr) != 1)
- goto end;
- SSL_set_connect_state(client);
- if (!SSL_set_incoming_stream_policy(client,
- SSL_INCOMING_STREAM_POLICY_ACCEPT,
- 0))
- goto end;
- allstreams[0] = stream = client;
- for (;;) {
- size_t size;
- uint64_t nxtpktms = 0;
- OSSL_TIME nxtpkt = ossl_time_zero(), nxttimeout;
- int isinf, ret = 0;
- if (len >= 2) {
- if (len >= 5 && buf[0] == 0xff && buf[1] == 0xff) {
- switch (buf[2]) {
- case 0x00:
- if (state == READING)
- state = ACCEPTING_STREAM;
- break;
- case 0x01:
- if (state == READING)
- state = CREATING_STREAM;
- break;
- case 0x02:
- if (state == READING)
- state = SWAPPING_STREAM;
- break;
- default:
- /*ignore*/
- break;
- }
- len -= 3;
- buf += 3;
- }
- nxtpktms = buf[0] + (buf[1] << 8);
- nxtpkt = ossl_time_add(fake_now, ossl_ms2time(nxtpktms));
- len -= 2;
- buf += 2;
- }
- for (;;) {
- switch (state) {
- case HANDSHAKING:
- ret = SSL_do_handshake(stream);
- if (ret == 1)
- state = READING;
- break;
- case READING:
- ret = SSL_read(stream, tmp, sizeof(tmp));
- if (ret > 0) {
- state = WRITING;
- writelen = ret;
- assert(writelen <= (int)sizeof(tmp));
- }
- break;
- case WRITING:
- ret = SSL_write(stream, tmp, writelen);
- if (ret > 0)
- state = READING;
- break;
- case ACCEPTING_STREAM:
- state = READING;
- ret = 1;
- if (numstreams == OSSL_NELEM(allstreams)
- || SSL_get_accept_stream_queue_len(client) == 0)
- break;
- thisstream = numstreams;
- stream = allstreams[numstreams++]
- = SSL_accept_stream(client, 0);
- if (stream == NULL)
- goto end;
- break;
- case CREATING_STREAM:
- state = READING;
- ret = 1;
- if (numstreams == OSSL_NELEM(allstreams))
- break;
- stream = SSL_new_stream(client, 0);
- if (stream == NULL) {
- /* Ignore, and go back to the previous stream */
- stream = allstreams[thisstream];
- break;
- }
- thisstream = numstreams;
- allstreams[numstreams++] = stream;
- break;
- case SWAPPING_STREAM:
- state = READING;
- ret = 1;
- if (numstreams == 1)
- break;
- if (++thisstream == numstreams)
- thisstream = 0;
- stream = allstreams[thisstream];
- break;
- }
- assert(stream != NULL);
- assert(thisstream < numstreams);
- if (ret <= 0) {
- switch (SSL_get_error(stream, ret)) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- break;
- default:
- goto end;
- }
- }
- if (!SSL_get_event_timeout(client, &tv, &isinf))
- goto end;
- if (isinf) {
- fake_now = nxtpkt;
- break;
- } else {
- nxttimeout = ossl_time_add(fake_now,
- ossl_time_from_timeval(tv));
- if (len > 3 && ossl_time_compare(nxttimeout, nxtpkt) >= 0) {
- fake_now = nxtpkt;
- break;
- }
- fake_now = nxttimeout;
- }
- }
- if (len <= 3)
- break;
- size = buf[0] + (buf[1] << 8);
- if (size > len - 2)
- break;
- if (size > 0)
- BIO_write(in, buf+2, size);
- len -= size + 2;
- buf += size + 2;
- }
- end:
- for (i = 0; i < numstreams; i++)
- SSL_free(allstreams[i]);
- ERR_clear_error();
- SSL_CTX_free(ctx);
- BIO_ADDR_free(peer_addr);
- return 0;
- }
- void FuzzerCleanup(void)
- {
- FuzzerClearRand();
- }
|