From: Greensi7 Date: Mon, 20 Jul 2026 21:34:08 +0000 (+0200) Subject: Add OSSL_ECHSTORE_read_echconfiglist fuzzer X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=10413cceb66411389bbd65a9e4698dc6a172113c;p=thirdparty%2Fopenssl.git Add OSSL_ECHSTORE_read_echconfiglist fuzzer Fuzz OSSL_ECHSTORE_read_echconfiglist with raw fuzzer input in stage 1. Then fixup the starting bytes to reach deeper code withotu relying only on corpus. Fixup is done for binary encoding only (not base64). Assisted-by: ChatGPT:gpt-5.5 Reviewed-by: Milan Broz Reviewed-by: Nikola Pajkovsky Reviewed-by: Norbert Pocs MergeDate: Thu Jul 23 13:57:54 2026 (Merged from https://github.com/openssl/openssl/pull/32021) --- diff --git a/fuzz/build.info b/fuzz/build.info index 5c410260e4c..fcbb76234cc 100644 --- a/fuzz/build.info +++ b/fuzz/build.info @@ -50,6 +50,10 @@ IF[{- !$disabled{"fuzz-afl"} || !$disabled{"fuzz-libfuzzer"} -}] PROGRAMS{noinst}=dtlsclient dtlsserver ENDIF + IF[{- !$disabled{"ech"} -}] + PROGRAMS{noinst}=echconfiglist_parser + ENDIF + SOURCE[asn1]=asn1.c driver.c fuzz_rand.c INCLUDE[asn1]=../include {- $ex_inc -} DEPEND[asn1]=../libcrypto ../libssl {- $ex_lib -} @@ -106,6 +110,10 @@ IF[{- !$disabled{"fuzz-afl"} || !$disabled{"fuzz-libfuzzer"} -}] INCLUDE[dtlsserver]=../include {- $ex_inc -} DEPEND[dtlsserver]=../libcrypto ../libssl {- $ex_lib -} + SOURCE[echconfiglist_parser]=echconfiglist_parser.c driver.c + INCLUDE[echconfiglist_parser]=../include {- $ex_inc -} + DEPEND[echconfiglist_parser]=../libcrypto ../libssl {- $ex_lib -} + SOURCE[pem]=pem.c driver.c INCLUDE[pem]=../include {- $ex_inc -} DEPEND[pem]=../libcrypto.a {- $ex_lib -} @@ -220,6 +228,10 @@ IF[{- !$disabled{tests} -}] PROGRAMS{noinst}=dtlsclient-test dtlsserver-test ENDIF + IF[{- !$disabled{"ech"} -}] + PROGRAMS{noinst}=echconfiglist_parser-test + ENDIF + SOURCE[asn1-test]=asn1.c $FUZZTESTSRC fuzz_rand.c INCLUDE[asn1-test]=../include ../test/mfail DEPEND[asn1-test]=../libcrypto.a ../libssl.a @@ -288,6 +300,10 @@ IF[{- !$disabled{tests} -}] INCLUDE[dtlsserver-test]=../include ../test/mfail DEPEND[dtlsserver-test]=../libcrypto.a ../libssl.a + SOURCE[echconfiglist_parser-test]=echconfiglist_parser.c $FUZZTESTSRC + INCLUDE[echconfiglist_parser-test]=../include ../test/mfail + DEPEND[echconfiglist_parser-test]=../libcrypto.a ../libssl.a + SOURCE[pem-test]=pem.c $FUZZTESTSRC INCLUDE[pem-test]=../include ../test/mfail DEPEND[pem-test]=../libcrypto.a diff --git a/fuzz/echconfiglist_parser.c b/fuzz/echconfiglist_parser.c new file mode 100644 index 00000000000..fce416ec4d8 --- /dev/null +++ b/fuzz/echconfiglist_parser.c @@ -0,0 +1,88 @@ +/* + * Copyright 2026 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 "fuzzer.h" + +static void parse_one(const uint8_t *buf, int len) +{ + OSSL_ECHSTORE *es; + BIO *in; + + es = OSSL_ECHSTORE_new(NULL, NULL); + if (es == NULL) + return; + + in = BIO_new_mem_buf(buf, len); + if (in == NULL) { + OSSL_ECHSTORE_free(es); + return; + } + + OSSL_ECHSTORE_read_echconfiglist(es, in); + + OSSL_ECHSTORE_free(es); + BIO_free(in); +} + +int FuzzerInitialize(int *argc, char ***argv) +{ + return 1; +} + +int FuzzerTestOneInput(const uint8_t *buf, size_t len) +{ + uint8_t *fixed_buf = NULL; + int bio_len; + uint16_t outer_len, inner_len; + + if (len > INT_MAX) + return 0; + bio_len = (int)len; + + /* Target raw without any fixup */ + parse_one(buf, bio_len); + + /* + * ech_decode_and_flatten has a strict size check: + * OSSL_ECH_MIN_ECHCONFIG_LEN = 32 + * OSSL_ECH_MAX_ECHCONFIG_LEN = 1500 + */ + if (len < OSSL_ECH_MIN_ECHCONFIG_LEN || len >= OSSL_ECH_MAX_ECHCONFIG_LEN) + goto end; + outer_len = (uint16_t)(len - 2); + inner_len = (uint16_t)(len - 6); + + fixed_buf = OPENSSL_memdup(buf, len); + if (fixed_buf == NULL) + goto end; + + /* Fix up to pass initial checks*/ + OPENSSL_store_u16_be(fixed_buf, outer_len); + OPENSSL_store_u16_be(fixed_buf + 2, OSSL_ECH_RFC9849_VERSION); + OPENSSL_store_u16_be(fixed_buf + 4, inner_len); + + parse_one(fixed_buf, bio_len); + +end: + OPENSSL_free(fixed_buf); + ERR_clear_error(); + + return 0; +} + +void FuzzerCleanup(void) +{ +} diff --git a/test/recipes/99-test_fuzz_echconfiglist_parser.t b/test/recipes/99-test_fuzz_echconfiglist_parser.t new file mode 100644 index 00000000000..09e115caa65 --- /dev/null +++ b/test/recipes/99-test_fuzz_echconfiglist_parser.t @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +# Copyright 2026 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 can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +use strict; +use warnings; + +use OpenSSL::Test qw/:DEFAULT srctop_file/; +use OpenSSL::Test::Utils; + +my $fuzzer = "echconfiglist_parser"; +setup("test_fuzz_${fuzzer}"); + +plan skip_all => "This test requires ech support" + if disabled("ech"); + +plan tests => 2; # one more due to below require_ok(...) + +require_ok(srctop_file('test','recipes','fuzz.pl')); + +fuzz_ok($fuzzer);