From ee7729ed4cfcfb95a3fc0aaa184ed624f3fb7eaa Mon Sep 17 00:00:00 2001 From: Kurt Roeckx Date: Wed, 23 Nov 2022 14:24:13 +0100 Subject: [PATCH] Add quic client fuzzer. Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22368) --- fuzz/build.info | 16 ++++++ fuzz/quic-client.c | 139 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 fuzz/quic-client.c diff --git a/fuzz/build.info b/fuzz/build.info index 7efc52ef85..a068c2f230 100644 --- a/fuzz/build.info +++ b/fuzz/build.info @@ -29,6 +29,10 @@ IF[{- !$disabled{"fuzz-afl"} || !$disabled{"fuzz-libfuzzer"} -}] PROGRAMS{noinst}=x509 ENDIF + IF[{- !$disabled{"quic"} -}] + PROGRAMS{noinst}=quic-client + ENDIF + SOURCE[asn1]=asn1.c driver.c fuzz_rand.c INCLUDE[asn1]=../include {- $ex_inc -} DEPEND[asn1]=../libcrypto ../libssl {- $ex_lib -} @@ -89,6 +93,10 @@ IF[{- !$disabled{"fuzz-afl"} || !$disabled{"fuzz-libfuzzer"} -}] INCLUDE[v3name]=../include {- $ex_inc -} DEPEND[v3name]=../libcrypto.a {- $ex_lib -} + SOURCE[quic-client]=quic-client.c driver.c fuzz_rand.c + INCLUDE[quic-client]=../include {- $ex_inc -} + DEPEND[quic-client]=../libcrypto ../libssl {- $ex_lib -} + SOURCE[server]=server.c driver.c fuzz_rand.c INCLUDE[server]=../include {- $ex_inc -} DEPEND[server]=../libcrypto ../libssl {- $ex_lib -} @@ -119,6 +127,10 @@ IF[{- !$disabled{tests} -}] PROGRAMS{noinst}=x509-test ENDIF + IF[{- !$disabled{"quic"} -}] + PROGRAMS{noinst}=quic-client-test + ENDIF + SOURCE[asn1-test]=asn1.c test-corpus.c fuzz_rand.c INCLUDE[asn1-test]=../include DEPEND[asn1-test]=../libcrypto ../libssl @@ -180,6 +192,10 @@ IF[{- !$disabled{tests} -}] INCLUDE[v3name-test]=../include DEPEND[v3name-test]=../libcrypto.a + SOURCE[quic-client-test]=quic-client.c test-corpus.c fuzz_rand.c + INCLUDE[quic-client-test]=../include + DEPEND[quic-client-test]=../libcrypto ../libssl + SOURCE[server-test]=server.c test-corpus.c fuzz_rand.c INCLUDE[server-test]=../include DEPEND[server-test]=../libcrypto ../libssl diff --git a/fuzz/quic-client.c b/fuzz/quic-client.c new file mode 100644 index 0000000000..c172372af3 --- /dev/null +++ b/fuzz/quic-client.c @@ -0,0 +1,139 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include "fuzzer.h" +#include "internal/sockets.h" + +/* unused, to avoid warning. */ +static int idx; + +#define FUZZTIME 1485898104 + +#define TIME_IMPL(t) { if (t != NULL) *t = FUZZTIME; return FUZZTIME; } + +/* + * This might not work in all cases (and definitely not on Windows + * because of the way linkers are) and callees can still get the + * current time instead of the fixed time. This will just result + * in things not being fully reproducible and have a slightly + * different coverage. + */ +#if !defined(_WIN32) +time_t time(time_t *t) TIME_IMPL(t) +#endif + +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; +} + +int FuzzerTestOneInput(const uint8_t *buf, size_t len) +{ + SSL *client = NULL; + BIO *in; + BIO *out; + SSL_CTX *ctx; + BIO_ADDR *peer_addr = NULL; + struct in_addr ina = {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; + + 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; + + /* + OPENSSL_assert(SSL_set_min_proto_version(client, 0) == 1); + OPENSSL_assert(SSL_set_cipher_list(client, "ALL:eNULL:@SECLEVEL=0") == 1); + */ + 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 (SSL_set_alpn_protos(client, (const unsigned char *)"\x08quicfuzz", 9) != 0) + goto end; + SSL_set_bio(client, in, out); + if (SSL_set1_initial_peer_addr(client, peer_addr) != 1) + goto end; + SSL_set_connect_state(client); + while (len > 3) + { + size_t size = buf[0] + (buf[1] << 8); + + if (size > len - 2) + break; + + if (size > 0) + /* OPENSSL_assert((size_t)BIO_write(in, buf+2, size) == size); */ + BIO_write(in, buf+2, size); + len -= size + 2; + buf += size + 2; + + if (SSL_do_handshake(client) == 1) { + /* Keep reading application data until error or EOF. */ + uint8_t tmp[1024]; + if (SSL_read(client, tmp, sizeof(tmp)) <= 0) + break; + } + } + end: + SSL_free(client); + ERR_clear_error(); + SSL_CTX_free(ctx); + BIO_ADDR_free(peer_addr); + + return 0; +} + +void FuzzerCleanup(void) +{ + FuzzerClearRand(); +}