diff options
-rw-r--r-- | configure.ac | 14 | ||||
-rw-r--r-- | devel/fuzz/README.md | 2 | ||||
-rw-r--r-- | lib/handshake.c | 12 | ||||
-rw-r--r-- | lib/nettle/Makefile.am | 4 | ||||
-rw-r--r-- | lib/nettle/rnd-fuzzer.c | 142 | ||||
-rw-r--r-- | lib/random.c | 11 | ||||
-rw-r--r-- | lib/x509/common.h | 7 |
7 files changed, 189 insertions, 3 deletions
diff --git a/configure.ac b/configure.ac index bce0d9f7ab..4ae4c0bc4e 100644 --- a/configure.ac +++ b/configure.ac @@ -248,6 +248,14 @@ AC_ARG_ENABLE(tests, enable_tests=$enableval, enable_tests=$enable_tools) AM_CONDITIONAL(ENABLE_TESTS, test "$enable_tests" != "no") +AC_ARG_ENABLE(fuzzer-target, + AS_HELP_STRING([--enable-fuzzer-target], [make a library intended for testing - not production]), + enable_fuzzer_target=$enableval, enable_fuzzer_target=no) +AM_CONDITIONAL(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION, test "$enable_fuzzer_target" != "no") +if test "$enable_fuzzer_target" != "no";then + AC_DEFINE([FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION], 1, [Enable fuzzer target -not for production]) +fi + GTK_DOC_CHECK(1.1) AM_GNU_GETTEXT([external]) AM_GNU_GETTEXT_VERSION([0.19]) @@ -1043,3 +1051,9 @@ AC_MSG_WARN([[ *** applications to link, do not enable static linking. ]]) fi + +if test "$enable_fuzzer_target" != "no";then +AC_MSG_WARN([[ +*** This version of the library is for fuzzying purposes and is intentionally broken! +]]) +fi diff --git a/devel/fuzz/README.md b/devel/fuzz/README.md index 575f80e091..0d94bbae15 100644 --- a/devel/fuzz/README.md +++ b/devel/fuzz/README.md @@ -18,7 +18,7 @@ using other projects like openssl. Use the following commands on top dir: ``` -$ CC="afl-gcc" ./configure +$ CC="afl-gcc" ./configure --enable-fuzzer-target $ make -j$(nproc) $ cd devel/fuzz $ make gnutls_pkcs7_parser_fuzzer diff --git a/lib/handshake.c b/lib/handshake.c index 8dc3fa58ec..d0e3d497bd 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -186,9 +186,14 @@ static int create_tls_random(uint8_t * dst) * system's time. */ +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) + /* When fuzzying avoid timing dependencies */ + memset(dst, 1, 4); +#else tim = gnutls_time(NULL); /* generate server random value */ _gnutls_write_uint32(tim, dst); +#endif ret = gnutls_rnd(GNUTLS_RND_NONCE, &dst[3], GNUTLS_RANDOM_SIZE - 3); @@ -793,11 +798,18 @@ static int _gnutls_recv_finished(gnutls_session_t session) goto cleanup; } +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) + /* When fuzzying allow to proceed without verifying the handshake + * consistency */ +# warning This is unsafe for production builds + +#else if (memcmp(vrfy, data, data_size) != 0) { gnutls_assert(); ret = GNUTLS_E_ERROR_IN_FINISHED_PACKET; goto cleanup; } +#endif ret = _gnutls_ext_sr_finished(session, data, data_size, 1); if (ret < 0) { diff --git a/lib/nettle/Makefile.am b/lib/nettle/Makefile.am index 12d7f016ea..c7196ae307 100644 --- a/lib/nettle/Makefile.am +++ b/lib/nettle/Makefile.am @@ -53,6 +53,10 @@ libcrypto_la_SOURCES += sysrng-linux.c endif endif +if FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +libcrypto_la_SOURCES += rnd-fuzzer.c +endif + if ENABLE_FIPS140 libcrypto_la_SOURCES += rnd-fips.c int/drbg-aes-self-test.c \ int/drbg-aes.c int/drbg-aes.h diff --git a/lib/nettle/rnd-fuzzer.c b/lib/nettle/rnd-fuzzer.c new file mode 100644 index 0000000000..b48601fabf --- /dev/null +++ b/lib/nettle/rnd-fuzzer.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2017 Red Hat + * Copyright (C) 1995-2017 Free Software Foundation, Inc. + * This file is part of the GNU C Library. + * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, August 1995. + * + * This file is part of GnuTLS. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <drbg-aes.h> +#include <fips.h> + +#include "gnutls_int.h" +#include "errors.h" +#include <stdlib.h> +#include <rnd-common.h> + +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +# error 1 +#endif + +struct r48_rand_data { + unsigned short int __x[3]; /* Current state. */ + unsigned short int __old_x[3]; /* Old state. */ + unsigned short int __c; /* Additive const. in congruential formula. */ + unsigned short int __init; /* Flag for initializing. */ + __extension__ unsigned long long int __a; /* Factor in congruential + formula. */ +}; + +static int +__r48_rand_iterate(unsigned short int xsubi[3], struct r48_rand_data *buffer) +{ + uint64_t X; + uint64_t result; + + /* Initialize buffer, if not yet done. */ + if (unlikely(!buffer->__init)) { + buffer->__a = 0x5deece66dull; + buffer->__c = 0xb; + buffer->__init = 1; + } + + /* Do the real work. We choose a data type which contains at least + 48 bits. Because we compute the modulus it does not care how + many bits really are computed. */ + + X = (uint64_t) xsubi[2] << 32 | (uint32_t) xsubi[1] << 16 | xsubi[0]; + + result = X * buffer->__a + buffer->__c; + + xsubi[0] = result & 0xffff; + xsubi[1] = (result >> 16) & 0xffff; + xsubi[2] = (result >> 32) & 0xffff; + + return 0; +} + +static int +r48_r(unsigned short int xsubi[3], struct r48_rand_data *buffer, + long int *result) +{ + /* Compute next state. */ + if (__r48_rand_iterate(xsubi, buffer) < 0) + return -1; + + /* Store the result. */ + *result = (int32_t) ((xsubi[2] << 16) | xsubi[1]); + + return 0; +} + +static int r48(struct r48_rand_data *buffer, long int *result) +{ + return r48_r(buffer->__x, buffer, result); +} + +/* This is a dummy random generator intended to be reproducible + * for use in fuzzying targets. + */ + +static int _rngfuzz_init(void **_ctx) +{ + *_ctx = calloc(1, sizeof(struct r48_rand_data)); + + return 0; +} + +static int _rngfuzz_rnd(void *_ctx, int level, void *buffer, size_t length) +{ + struct r48_rand_data *ctx = _ctx; + uint8_t *p = buffer; + long r; + unsigned i; + + memset(ctx, 0, sizeof(*ctx)); + + for (i = 0; i < length; i++) { + r48(ctx, &r); + p[i] = r; + } + return 0; +} + +static void _rngfuzz_deinit(void *_ctx) +{ + struct r48_rand_data *ctx = _ctx; + + free(ctx); +} + +static void _rngfuzz_refresh(void *_ctx) +{ + /* this is predictable RNG. Don't refresh */ + return; +} + +gnutls_crypto_rnd_st _gnutls_fuzz_rnd_ops = { + .init = _rngfuzz_init, + .deinit = _rngfuzz_deinit, + .rnd = _rngfuzz_rnd, + .rnd_refresh = _rngfuzz_refresh, + .self_test = NULL, +}; diff --git a/lib/random.c b/lib/random.c index 2fe82adc7d..0c05dbe187 100644 --- a/lib/random.c +++ b/lib/random.c @@ -37,6 +37,9 @@ # error Unsupported platform #endif +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) +extern gnutls_crypto_rnd_st _gnutls_fuzz_rnd_ops; +#endif /* Per thread context of random generator, and a flag to indicate initialization */ static _Thread_local void *gnutls_rnd_ctx; @@ -100,7 +103,13 @@ int _gnutls_rnd_preinit(void) { int ret; -#ifdef ENABLE_FIPS140 +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) +# warning Insecure PRNG is enabled + ret = gnutls_crypto_rnd_register(100, &_gnutls_fuzz_rnd_ops); + if (ret < 0) + return ret; + +#elif defined(ENABLE_FIPS140) /* The FIPS140 random generator is only enabled when we are compiled * with FIPS support, _and_ the system requires FIPS140. */ diff --git a/lib/x509/common.h b/lib/x509/common.h index eafc7a515b..1a27666076 100644 --- a/lib/x509/common.h +++ b/lib/x509/common.h @@ -30,9 +30,14 @@ #include <fips.h> #define MAX_STRING_LEN 512 + +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) +# define MAX_ITER_COUNT 10*1024 +#else /* Set a maximum iteration count over which we refuse to * decode a file. That is to prevent DoS. */ -#define MAX_ITER_COUNT (10*1024*1024) +# define MAX_ITER_COUNT (10*1024*1024) +#endif #define GNUTLS_XML_SHOW_ALL 1 |