Home | History | Annotate | Line # | Download | only in fuzz
      1 /*
      2  * Copyright 2016-2025 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 #define HANDSHAKING 0
     47 #define READING 1
     48 #define WRITING 2
     49 #define ACCEPTING_STREAM 3
     50 #define CREATING_STREAM 4
     51 #define SWAPPING_STREAM 5
     52 
     53 int FuzzerTestOneInput(const uint8_t *buf, size_t len)
     54 {
     55     SSL *client = NULL, *stream = NULL;
     56     SSL *allstreams[] = { NULL, NULL, NULL, NULL };
     57     size_t i, thisstream = 0, numstreams = 1;
     58     BIO *in;
     59     BIO *out;
     60     SSL_CTX *ctx;
     61     BIO_ADDR *peer_addr = NULL;
     62     struct in_addr ina = { 0 };
     63     struct timeval tv;
     64     int state = HANDSHAKING;
     65     uint8_t tmp[1024];
     66     int writelen = 0;
     67 
     68     if (len == 0)
     69         return 0;
     70 
     71     /* This only fuzzes the initial flow from the client so far. */
     72     ctx = SSL_CTX_new(OSSL_QUIC_client_method());
     73     if (ctx == NULL)
     74         goto end;
     75 
     76     client = SSL_new(ctx);
     77     if (client == NULL)
     78         goto end;
     79 
     80     fake_now = ossl_ms2time(1);
     81     if (!ossl_quic_set_override_now_cb(client, fake_now_cb, NULL))
     82         goto end;
     83 
     84     peer_addr = BIO_ADDR_new();
     85     if (peer_addr == NULL)
     86         goto end;
     87 
     88     ina.s_addr = htonl(0x7f000001UL);
     89 
     90     if (!BIO_ADDR_rawmake(peer_addr, AF_INET, &ina, sizeof(ina), htons(4433)))
     91         goto end;
     92 
     93     SSL_set_tlsext_host_name(client, "localhost");
     94     in = BIO_new(BIO_s_dgram_mem());
     95     if (in == NULL)
     96         goto end;
     97     out = BIO_new(BIO_s_dgram_mem());
     98     if (out == NULL) {
     99         BIO_free(in);
    100         goto end;
    101     }
    102     if (!BIO_dgram_set_caps(out, BIO_DGRAM_CAP_HANDLES_DST_ADDR)) {
    103         BIO_free(in);
    104         BIO_free(out);
    105         goto end;
    106     }
    107     SSL_set_bio(client, in, out);
    108     if (SSL_set_alpn_protos(client, (const unsigned char *)"\x08ossltest", 9) != 0)
    109         goto end;
    110     if (SSL_set1_initial_peer_addr(client, peer_addr) != 1)
    111         goto end;
    112     SSL_set_connect_state(client);
    113 
    114     if (!SSL_set_incoming_stream_policy(client,
    115             SSL_INCOMING_STREAM_POLICY_ACCEPT,
    116             0))
    117         goto end;
    118 
    119     allstreams[0] = stream = client;
    120     for (;;) {
    121         size_t size;
    122         uint64_t nxtpktms = 0;
    123         OSSL_TIME nxtpkt = ossl_time_zero(), nxttimeout;
    124         int isinf, ret = 0;
    125 
    126         if (len >= 2) {
    127             if (len >= 5 && buf[0] == 0xff && buf[1] == 0xff) {
    128                 switch (buf[2]) {
    129                 case 0x00:
    130                     if (state == READING)
    131                         state = ACCEPTING_STREAM;
    132                     break;
    133                 case 0x01:
    134                     if (state == READING)
    135                         state = CREATING_STREAM;
    136                     break;
    137                 case 0x02:
    138                     if (state == READING)
    139                         state = SWAPPING_STREAM;
    140                     break;
    141                 default:
    142                     /*ignore*/
    143                     break;
    144                 }
    145                 len -= 3;
    146                 buf += 3;
    147             }
    148             nxtpktms = buf[0] + (buf[1] << 8);
    149             nxtpkt = ossl_time_add(fake_now, ossl_ms2time(nxtpktms));
    150             len -= 2;
    151             buf += 2;
    152         }
    153 
    154         for (;;) {
    155             switch (state) {
    156             case HANDSHAKING:
    157                 ret = SSL_do_handshake(stream);
    158                 if (ret == 1)
    159                     state = READING;
    160                 break;
    161 
    162             case READING:
    163                 ret = SSL_read(stream, tmp, sizeof(tmp));
    164                 if (ret > 0) {
    165                     state = WRITING;
    166                     writelen = ret;
    167                     assert(writelen <= (int)sizeof(tmp));
    168                 }
    169                 break;
    170 
    171             case WRITING:
    172                 ret = SSL_write(stream, tmp, writelen);
    173                 if (ret > 0)
    174                     state = READING;
    175                 break;
    176 
    177             case ACCEPTING_STREAM:
    178                 state = READING;
    179                 ret = 1;
    180                 if (numstreams == OSSL_NELEM(allstreams)
    181                     || SSL_get_accept_stream_queue_len(client) == 0)
    182                     break;
    183                 thisstream = numstreams;
    184                 stream = allstreams[numstreams++]
    185                     = SSL_accept_stream(client, 0);
    186                 if (stream == NULL)
    187                     goto end;
    188                 break;
    189 
    190             case CREATING_STREAM:
    191                 state = READING;
    192                 ret = 1;
    193                 if (numstreams == OSSL_NELEM(allstreams))
    194                     break;
    195                 stream = SSL_new_stream(client, 0);
    196                 if (stream == NULL) {
    197                     /* Ignore, and go back to the previous stream */
    198                     stream = allstreams[thisstream];
    199                     break;
    200                 }
    201                 thisstream = numstreams;
    202                 allstreams[numstreams++] = stream;
    203                 break;
    204 
    205             case SWAPPING_STREAM:
    206                 state = READING;
    207                 ret = 1;
    208                 if (numstreams == 1)
    209                     break;
    210                 if (++thisstream == numstreams)
    211                     thisstream = 0;
    212                 stream = allstreams[thisstream];
    213                 break;
    214             }
    215             assert(stream != NULL);
    216             assert(thisstream < numstreams);
    217             if (ret <= 0) {
    218                 switch (SSL_get_error(stream, ret)) {
    219                 case SSL_ERROR_WANT_READ:
    220                 case SSL_ERROR_WANT_WRITE:
    221                     break;
    222                 default:
    223                     goto end;
    224                 }
    225             }
    226 
    227             if (!SSL_get_event_timeout(client, &tv, &isinf))
    228                 goto end;
    229 
    230             if (isinf) {
    231                 fake_now = nxtpkt;
    232                 break;
    233             } else {
    234                 nxttimeout = ossl_time_add(fake_now,
    235                     ossl_time_from_timeval(tv));
    236                 if (len > 3 && ossl_time_compare(nxttimeout, nxtpkt) >= 0) {
    237                     fake_now = nxtpkt;
    238                     break;
    239                 }
    240                 fake_now = nxttimeout;
    241             }
    242         }
    243 
    244         if (len <= 3)
    245             break;
    246 
    247         size = buf[0] + (buf[1] << 8);
    248         if (size > len - 2)
    249             break;
    250 
    251         if (size > 0)
    252             BIO_write(in, buf + 2, size);
    253         len -= size + 2;
    254         buf += size + 2;
    255     }
    256 end:
    257     for (i = 0; i < numstreams; i++)
    258         SSL_free(allstreams[i]);
    259     ERR_clear_error();
    260     SSL_CTX_free(ctx);
    261     BIO_ADDR_free(peer_addr);
    262 
    263     return 0;
    264 }
    265 
    266 void FuzzerCleanup(void)
    267 {
    268     FuzzerClearRand();
    269 }
    270