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