Home | History | Annotate | Line # | Download | only in fuzz
      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