summaryrefslogtreecommitdiff
path: root/fuzz
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2020-10-23 23:10:20 +0800
committerMatt Johnston <matt@ucc.asn.au>2020-10-23 23:10:20 +0800
commit12b5f209126c7a347d7ae79bd0b8802477cb08f1 (patch)
tree4459d295f1cebe483bab2873d109dd11b656d4bb /fuzz
parent9a5ad3c8a5f5af02370ab920d3fbb7dd7b097b98 (diff)
downloaddropbear-12b5f209126c7a347d7ae79bd0b8802477cb08f1.tar.gz
Move fuzzing code to fuzz/ subdirectory, improve Makefile.in
Diffstat (limited to 'fuzz')
-rw-r--r--fuzz/fuzz-common.c311
-rw-r--r--fuzz/fuzz-harness.c48
-rw-r--r--fuzz/fuzz-hostkeys.c140
-rw-r--r--fuzz/fuzz-wrapfd.c241
-rw-r--r--fuzz/fuzzer-client.c6
-rw-r--r--fuzz/fuzzer-client_nomaths.c6
-rw-r--r--fuzz/fuzzer-kexcurve25519.c72
-rw-r--r--fuzz/fuzzer-kexdh.c76
-rw-r--r--fuzz/fuzzer-kexecdh.c82
-rw-r--r--fuzz/fuzzer-preauth.c6
-rw-r--r--fuzz/fuzzer-preauth_nomaths.c6
-rw-r--r--fuzz/fuzzer-pubkey.c54
-rw-r--r--fuzz/fuzzer-verify.c79
13 files changed, 1127 insertions, 0 deletions
diff --git a/fuzz/fuzz-common.c b/fuzz/fuzz-common.c
new file mode 100644
index 0000000..60dab21
--- /dev/null
+++ b/fuzz/fuzz-common.c
@@ -0,0 +1,311 @@
+#include "includes.h"
+
+#include "includes.h"
+#include "fuzz.h"
+#include "dbutil.h"
+#include "runopts.h"
+#include "crypto_desc.h"
+#include "session.h"
+#include "dbrandom.h"
+#include "bignum.h"
+#include "atomicio.h"
+#include "fuzz-wrapfd.h"
+
+struct dropbear_fuzz_options fuzz;
+
+static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param);
+static void load_fixed_hostkeys(void);
+static void load_fixed_client_key(void);
+
+void fuzz_common_setup(void) {
+ disallow_core();
+ fuzz.fuzzing = 1;
+ fuzz.wrapfds = 1;
+ fuzz.do_jmp = 1;
+ fuzz.input = m_malloc(sizeof(buffer));
+ _dropbear_log = fuzz_dropbear_log;
+ crypto_init();
+ fuzz_seed();
+ /* let any messages get flushed */
+ setlinebuf(stdout);
+}
+
+int fuzz_set_input(const uint8_t *Data, size_t Size) {
+
+ fuzz.input->data = (unsigned char*)Data;
+ fuzz.input->size = Size;
+ fuzz.input->len = Size;
+ fuzz.input->pos = 0;
+
+ memset(&ses, 0x0, sizeof(ses));
+ memset(&svr_ses, 0x0, sizeof(svr_ses));
+ memset(&cli_ses, 0x0, sizeof(cli_ses));
+ wrapfd_setup(fuzz.input);
+
+ fuzz_seed();
+
+ return DROPBEAR_SUCCESS;
+}
+
+#if DEBUG_TRACE
+static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param) {
+ if (debug_trace) {
+ char printbuf[1024];
+ vsnprintf(printbuf, sizeof(printbuf), format, param);
+ fprintf(stderr, "%s\n", printbuf);
+ }
+}
+#else
+static void fuzz_dropbear_log(int UNUSED(priority), const char* UNUSED(format), va_list UNUSED(param)) {
+ /* No print */
+}
+#endif /* DEBUG_TRACE */
+
+void fuzz_svr_setup(void) {
+ fuzz_common_setup();
+
+ _dropbear_exit = svr_dropbear_exit;
+
+ char *argv[] = {
+ "dropbear",
+ "-E",
+ };
+
+ int argc = sizeof(argv) / sizeof(*argv);
+ svr_getopts(argc, argv);
+
+ load_fixed_hostkeys();
+}
+
+void fuzz_cli_setup(void) {
+ fuzz_common_setup();
+
+ _dropbear_exit = cli_dropbear_exit;
+ _dropbear_log = cli_dropbear_log;
+
+ char *argv[] = {
+ "dbclient",
+ "-y",
+ "localhost",
+ "uptime"
+ };
+
+ int argc = sizeof(argv) / sizeof(*argv);
+ cli_getopts(argc, argv);
+
+ load_fixed_client_key();
+ /* Avoid password prompt */
+ setenv(DROPBEAR_PASSWORD_ENV, "password", 1);
+}
+
+#include "fuzz-hostkeys.c"
+
+static void load_fixed_client_key(void) {
+
+ buffer *b = buf_new(3000);
+ sign_key *key;
+ enum signkey_type keytype;
+
+ key = new_sign_key();
+ keytype = DROPBEAR_SIGNKEY_ANY;
+ buf_putbytes(b, keyed25519, keyed25519_len);
+ buf_setpos(b, 0);
+ if (buf_get_priv_key(b, key, &keytype) == DROPBEAR_FAILURE) {
+ dropbear_exit("failed fixed ed25519 hostkey");
+ }
+ list_append(cli_opts.privkeys, key);
+
+ buf_free(b);
+}
+
+static void load_fixed_hostkeys(void) {
+
+ buffer *b = buf_new(3000);
+ enum signkey_type type;
+
+ TRACE(("load fixed hostkeys"))
+
+ svr_opts.hostkey = new_sign_key();
+
+ buf_setlen(b, 0);
+ buf_putbytes(b, keyr, keyr_len);
+ buf_setpos(b, 0);
+ type = DROPBEAR_SIGNKEY_RSA;
+ if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
+ dropbear_exit("failed fixed rsa hostkey");
+ }
+
+ buf_setlen(b, 0);
+ buf_putbytes(b, keyd, keyd_len);
+ buf_setpos(b, 0);
+ type = DROPBEAR_SIGNKEY_DSS;
+ if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
+ dropbear_exit("failed fixed dss hostkey");
+ }
+
+ buf_setlen(b, 0);
+ buf_putbytes(b, keye, keye_len);
+ buf_setpos(b, 0);
+ type = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
+ if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
+ dropbear_exit("failed fixed ecdsa hostkey");
+ }
+
+ buf_setlen(b, 0);
+ buf_putbytes(b, keyed25519, keyed25519_len);
+ buf_setpos(b, 0);
+ type = DROPBEAR_SIGNKEY_ED25519;
+ if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
+ dropbear_exit("failed fixed ed25519 hostkey");
+ }
+
+ buf_free(b);
+}
+
+void fuzz_kex_fakealgos(void) {
+ ses.newkeys->recv.crypt_mode = &dropbear_mode_none;
+}
+
+void fuzz_get_socket_address(int UNUSED(fd), char **local_host, char **local_port,
+ char **remote_host, char **remote_port, int UNUSED(host_lookup)) {
+ if (local_host) {
+ *local_host = m_strdup("fuzzlocalhost");
+ }
+ if (local_port) {
+ *local_port = m_strdup("1234");
+ }
+ if (remote_host) {
+ *remote_host = m_strdup("fuzzremotehost");
+ }
+ if (remote_port) {
+ *remote_port = m_strdup("9876");
+ }
+}
+
+/* cut down version of svr_send_msg_kexdh_reply() that skips slow maths. Still populates structures */
+void fuzz_fake_send_kexdh_reply(void) {
+ assert(!ses.dh_K);
+ m_mp_alloc_init_multi(&ses.dh_K, NULL);
+ mp_set_ul(ses.dh_K, 12345678uL);
+ finish_kexhashbuf();
+}
+
+/* fake version of spawn_command() */
+int fuzz_spawn_command(int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid) {
+ *ret_writefd = wrapfd_new();
+ *ret_readfd = wrapfd_new();
+ if (ret_errfd) {
+ *ret_errfd = wrapfd_new();
+ }
+ *ret_pid = 999;
+ return DROPBEAR_SUCCESS;
+}
+
+int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) {
+ static int once = 0;
+ if (!once) {
+ fuzz_svr_setup();
+ fuzz.skip_kexmaths = skip_kexmaths;
+ once = 1;
+ }
+
+ if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
+ return 0;
+ }
+
+ /*
+ get prefix, allowing for future extensibility. input format is
+ string prefix
+ uint32 wrapfd seed
+ ... to be extended later
+ [bytes] ssh input stream
+ */
+
+ /* be careful to avoid triggering buffer.c assertions */
+ if (fuzz.input->len < 8) {
+ return 0;
+ }
+ size_t prefix_size = buf_getint(fuzz.input);
+ if (prefix_size != 4) {
+ return 0;
+ }
+ uint32_t wrapseed = buf_getint(fuzz.input);
+ wrapfd_setseed(wrapseed);
+
+ int fakesock = wrapfd_new();
+
+ m_malloc_set_epoch(1);
+ if (setjmp(fuzz.jmp) == 0) {
+ svr_session(fakesock, fakesock);
+ m_malloc_free_epoch(1, 0);
+ } else {
+ m_malloc_free_epoch(1, 1);
+ TRACE(("dropbear_exit longjmped"))
+ /* dropbear_exit jumped here */
+ }
+
+ return 0;
+}
+
+int fuzz_run_client(const uint8_t *Data, size_t Size, int skip_kexmaths) {
+ static int once = 0;
+ if (!once) {
+ fuzz_cli_setup();
+ fuzz.skip_kexmaths = skip_kexmaths;
+ once = 1;
+ }
+
+ if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
+ return 0;
+ }
+
+ /*
+ get prefix, allowing for future extensibility. input format is
+ string prefix
+ uint32 wrapfd seed
+ ... to be extended later
+ [bytes] ssh input stream
+ */
+
+ /* be careful to avoid triggering buffer.c assertions */
+ if (fuzz.input->len < 8) {
+ return 0;
+ }
+ size_t prefix_size = buf_getint(fuzz.input);
+ if (prefix_size != 4) {
+ return 0;
+ }
+ uint32_t wrapseed = buf_getint(fuzz.input);
+ wrapfd_setseed(wrapseed);
+
+ int fakesock = wrapfd_new();
+
+ m_malloc_set_epoch(1);
+ if (setjmp(fuzz.jmp) == 0) {
+ cli_session(fakesock, fakesock, NULL, 0);
+ m_malloc_free_epoch(1, 0);
+ } else {
+ m_malloc_free_epoch(1, 1);
+ TRACE(("dropbear_exit longjmped"))
+ /* dropbear_exit jumped here */
+ }
+
+ return 0;
+}
+
+const void* fuzz_get_algo(const algo_type *algos, const char* name) {
+ const algo_type *t;
+ for (t = algos; t->name; t++) {
+ if (strcmp(t->name, name) == 0) {
+ return t->data;
+ }
+ }
+ assert(0);
+}
+
+void fuzz_dump(const unsigned char* data, size_t len) {
+ TRACE(("dump %zu", len))
+ if (fuzz.dumping) {
+ assert(atomicio(vwrite, fuzz.recv_dumpfd, (void*)data, len) == len);
+ }
+}
diff --git a/fuzz/fuzz-harness.c b/fuzz/fuzz-harness.c
new file mode 100644
index 0000000..ced707c
--- /dev/null
+++ b/fuzz/fuzz-harness.c
@@ -0,0 +1,48 @@
+#include "includes.h"
+#include "buffer.h"
+#include "dbutil.h"
+
+extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size);
+
+int main(int argc, char ** argv) {
+ int i;
+ buffer *input = buf_new(100000);
+
+ for (i = 1; i < argc; i++) {
+#if DEBUG_TRACE
+ if (strcmp(argv[i], "-v") == 0) {
+ debug_trace = 1;
+ TRACE(("debug printing on"))
+ }
+#endif
+ }
+
+ int old_fuzz_wrapfds = 0;
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ /* ignore arguments */
+ continue;
+ }
+
+ char* fn = argv[i];
+ buf_setlen(input, 0);
+ buf_readfile(input, fn);
+ buf_setpos(input, 0);
+
+ /* Run twice to catch problems with statefulness */
+ fuzz.wrapfds = old_fuzz_wrapfds;
+ printf("Running %s once \n", fn);
+ LLVMFuzzerTestOneInput(input->data, input->len);
+ printf("Running %s twice \n", fn);
+ LLVMFuzzerTestOneInput(input->data, input->len);
+ printf("Done %s\n", fn);
+
+ /* Disable wrapfd so it won't interfere with buf_readfile() above */
+ old_fuzz_wrapfds = fuzz.wrapfds;
+ fuzz.wrapfds = 0;
+ }
+
+ printf("Finished\n");
+
+ return 0;
+}
diff --git a/fuzz/fuzz-hostkeys.c b/fuzz/fuzz-hostkeys.c
new file mode 100644
index 0000000..128c8d1
--- /dev/null
+++ b/fuzz/fuzz-hostkeys.c
@@ -0,0 +1,140 @@
+/* To be included in fuzz-common.c */
+
+static unsigned char keyr[] = {
+ 0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x00,
+ 0x00, 0x00, 0x03, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0xb1,
+ 0x06, 0x95, 0xc9, 0xa8, 0x38, 0xb9, 0x99, 0x91, 0xb5, 0x17, 0x39, 0xb9,
+ 0xfa, 0xa4, 0x49, 0xf8, 0x2a, 0x4c, 0x14, 0xbd, 0xb6, 0x85, 0xdb, 0x38,
+ 0x99, 0x44, 0xfa, 0xd6, 0xaa, 0x67, 0xef, 0x00, 0x75, 0x2b, 0x6a, 0x5c,
+ 0x1b, 0x50, 0xa8, 0x52, 0xf9, 0xa7, 0xee, 0xe2, 0xb3, 0x80, 0x38, 0x92,
+ 0x20, 0x86, 0x7c, 0xe5, 0x89, 0xb3, 0x06, 0xe4, 0x3b, 0xd1, 0xe2, 0x45,
+ 0xea, 0xc1, 0xd5, 0x8e, 0x05, 0xfb, 0x90, 0x29, 0xd9, 0x41, 0xb3, 0x05,
+ 0x31, 0x1e, 0xcc, 0xeb, 0x89, 0xdc, 0xd2, 0x6a, 0x99, 0x23, 0xbd, 0x7a,
+ 0xbe, 0x8c, 0xe3, 0x3f, 0xa1, 0xe8, 0xf5, 0xb4, 0x51, 0x40, 0xb4, 0xb1,
+ 0xc1, 0x16, 0x9f, 0x07, 0xbb, 0x99, 0xaa, 0x4b, 0x8f, 0x11, 0x19, 0x3c,
+ 0x18, 0xbd, 0x6e, 0xce, 0x14, 0x54, 0x2c, 0x16, 0x4a, 0x5f, 0x89, 0xe4,
+ 0x6b, 0x9f, 0x55, 0x68, 0xcc, 0x09, 0x8e, 0x4b, 0x92, 0xc8, 0x87, 0xfe,
+ 0x09, 0xed, 0x53, 0x6e, 0xff, 0x5f, 0x15, 0x0d, 0x19, 0x9d, 0xa6, 0x54,
+ 0xd2, 0xea, 0x59, 0x4f, 0xa1, 0x7c, 0xf6, 0xf5, 0x7f, 0x32, 0x23, 0xed,
+ 0x72, 0xa8, 0x96, 0x17, 0x87, 0x06, 0xf2, 0xc7, 0xcd, 0xda, 0x4a, 0x10,
+ 0xd1, 0xfd, 0xb8, 0xf1, 0xaf, 0x25, 0x55, 0x32, 0x45, 0x39, 0x95, 0xec,
+ 0x0c, 0xa9, 0xf0, 0x47, 0x8b, 0x66, 0xe0, 0xb7, 0xa2, 0xf6, 0x35, 0x50,
+ 0x27, 0xe7, 0x2f, 0x90, 0x35, 0x5b, 0xd5, 0x62, 0x19, 0xb4, 0x41, 0xd4,
+ 0x52, 0xe7, 0x7f, 0x97, 0xfc, 0x5b, 0x4a, 0x5b, 0x19, 0x06, 0x65, 0x2d,
+ 0x23, 0x29, 0x15, 0x8b, 0x05, 0xaf, 0xbe, 0xd3, 0x4a, 0x27, 0x5b, 0xc9,
+ 0xc0, 0xd0, 0xd2, 0xba, 0x8b, 0x00, 0x7a, 0x2f, 0x39, 0xa0, 0x13, 0xb9,
+ 0xe6, 0xf5, 0x4b, 0x21, 0x54, 0x57, 0xb3, 0xf9, 0x6c, 0x6f, 0xd0, 0x17,
+ 0xf4, 0x50, 0x9d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xf2, 0xda, 0x5f, 0xfb,
+ 0xe2, 0xda, 0xfc, 0xe0, 0xdf, 0x3a, 0x0e, 0x14, 0x18, 0xc1, 0xd9, 0x1f,
+ 0x43, 0xe3, 0x65, 0x3e, 0x07, 0xe7, 0x8d, 0xdc, 0x1d, 0x11, 0xc1, 0xd6,
+ 0xc0, 0xd8, 0xda, 0x53, 0xf5, 0x04, 0x73, 0x51, 0x1b, 0x26, 0xef, 0x4e,
+ 0xf5, 0xce, 0x3d, 0x77, 0x21, 0x94, 0xd0, 0xc7, 0xc1, 0xda, 0x19, 0x7d,
+ 0xf8, 0xc5, 0x4c, 0xc8, 0xee, 0x7d, 0xd1, 0xbb, 0x02, 0x90, 0x2b, 0xff,
+ 0x4e, 0x4d, 0xd7, 0x9d, 0x72, 0x0c, 0x60, 0x0f, 0x4b, 0x83, 0xf5, 0xc2,
+ 0x26, 0xd6, 0x22, 0xb8, 0x60, 0x3a, 0xf9, 0x2f, 0x92, 0x2a, 0x2e, 0x14,
+ 0xa7, 0x56, 0x1c, 0x56, 0x05, 0x41, 0x92, 0xac, 0xb1, 0x4e, 0x44, 0x1e,
+ 0x70, 0x42, 0xda, 0xc7, 0xc8, 0x9c, 0xae, 0x29, 0x2d, 0x0c, 0x3a, 0xff,
+ 0x9b, 0xb6, 0xad, 0xb4, 0xfb, 0x49, 0x28, 0x96, 0x74, 0xf5, 0x94, 0x74,
+ 0xb7, 0x40, 0x93, 0x2b, 0x34, 0x29, 0xd2, 0x8a, 0xf3, 0x99, 0xf9, 0xe9,
+ 0xd8, 0xcc, 0x48, 0x1d, 0x3e, 0xc1, 0x82, 0x35, 0x4f, 0xef, 0xb1, 0x81,
+ 0x3c, 0xe1, 0xa1, 0x03, 0x65, 0xac, 0x21, 0x21, 0x40, 0x61, 0xfb, 0xd3,
+ 0x54, 0xac, 0xa1, 0xf2, 0xf0, 0x61, 0xd9, 0x01, 0x4e, 0xc2, 0x28, 0xb1,
+ 0x7c, 0x27, 0x6e, 0x56, 0x68, 0x69, 0x8f, 0xc5, 0xfd, 0xca, 0x39, 0x6e,
+ 0x22, 0x09, 0xf1, 0xb4, 0xd5, 0xac, 0xb8, 0xe0, 0x1b, 0x21, 0x86, 0xf4,
+ 0xc8, 0x15, 0xc6, 0x1f, 0x21, 0xae, 0xcb, 0xab, 0x5a, 0x09, 0x30, 0x9e,
+ 0xdd, 0x6c, 0x38, 0x59, 0xec, 0x59, 0x3a, 0x08, 0xee, 0x46, 0x7b, 0x78,
+ 0x23, 0xbc, 0xfc, 0xe2, 0xda, 0xe8, 0x1a, 0x65, 0xe6, 0xe0, 0x78, 0xd3,
+ 0xb0, 0x03, 0x2e, 0xf1, 0xb8, 0xca, 0x8e, 0x90, 0x75, 0xaf, 0xf7, 0xa8,
+ 0x48, 0xed, 0x82, 0xc9, 0xcf, 0x44, 0x56, 0xfc, 0x05, 0xfd, 0x6b, 0x00,
+ 0x00, 0x00, 0x81, 0x00, 0xfc, 0x94, 0xdf, 0x42, 0xc7, 0x9a, 0xa2, 0xff,
+ 0x32, 0xdf, 0x06, 0xb6, 0x4d, 0x90, 0x31, 0x28, 0x28, 0xdb, 0x03, 0xf9,
+ 0xa6, 0xb3, 0xa2, 0x91, 0x4c, 0xdf, 0x6e, 0xf6, 0xb9, 0x44, 0x3b, 0xdd,
+ 0x17, 0xc1, 0xc8, 0x1d, 0xd1, 0xc0, 0xc0, 0x30, 0x22, 0xbe, 0x24, 0x2e,
+ 0x0e, 0xdf, 0xe0, 0x18, 0x37, 0x3e, 0xb8, 0x7f, 0xb2, 0x50, 0x34, 0xc4,
+ 0x08, 0x5e, 0x69, 0x1f, 0xd5, 0xc9, 0xce, 0x47, 0x7d, 0x75, 0x5e, 0x3b,
+ 0x87, 0xdd, 0x46, 0x35, 0x01, 0x0f, 0x17, 0x8a, 0xf1, 0xf1, 0xc4, 0xa9,
+ 0x94, 0xa7, 0x6e, 0xce, 0x80, 0xe3, 0x17, 0x2e, 0xb0, 0xef, 0x63, 0xa7,
+ 0x11, 0x86, 0x96, 0x4a, 0x63, 0x2d, 0x9e, 0x92, 0x62, 0x43, 0x43, 0x72,
+ 0xa5, 0xdc, 0xa0, 0xcd, 0x19, 0x93, 0xd7, 0xe0, 0x80, 0x41, 0x27, 0xea,
+ 0xe4, 0xe8, 0xc1, 0x91, 0x9e, 0x13, 0xb3, 0x9c, 0xd1, 0xed, 0xcb, 0xbf,
+ 0x00, 0x00, 0x00, 0x81, 0x00, 0xb3, 0x6b, 0xee, 0xa4, 0x70, 0x4e, 0xfb,
+ 0xf9, 0x7e, 0x2e, 0x74, 0x5d, 0x3e, 0x8b, 0x3f, 0xff, 0x8c, 0xde, 0x68,
+ 0x38, 0xda, 0xce, 0xc0, 0x66, 0x4b, 0xca, 0x35, 0xc3, 0x97, 0xa8, 0xf0,
+ 0x00, 0x8e, 0xb3, 0x46, 0x60, 0xd0, 0x4d, 0x7e, 0x7b, 0xdf, 0x17, 0x7b,
+ 0x2f, 0xc4, 0x16, 0xee, 0x45, 0xdb, 0xa5, 0x5d, 0xc0, 0x72, 0xe9, 0xc6,
+ 0x91, 0x0f, 0xd9, 0x30, 0x74, 0x6c, 0xde, 0x93, 0xb5, 0xb6, 0xaf, 0x52,
+ 0x53, 0x3c, 0x08, 0x55, 0xea, 0xb8, 0x66, 0x07, 0xbe, 0xce, 0xf9, 0x80,
+ 0x8d, 0xe0, 0xca, 0xdc, 0x63, 0xe8, 0x58, 0x94, 0x22, 0x4f, 0x08, 0x66,
+ 0x13, 0x9e, 0x63, 0x2e, 0x92, 0x7a, 0xb6, 0x66, 0x94, 0x9b, 0x71, 0x66,
+ 0xd3, 0x08, 0xc9, 0x89, 0xea, 0x78, 0x35, 0x0d, 0xf2, 0x25, 0x55, 0xd4,
+ 0xb0, 0x9b, 0xea, 0x18, 0x77, 0xf6, 0x25, 0x02, 0xb4, 0x5e, 0x71, 0xea,
+ 0xa3
+};
+static unsigned int keyr_len = 805;
+static unsigned char keye[] = {
+ 0x00, 0x00, 0x00, 0x13, 0x65, 0x63, 0x64, 0x73, 0x61, 0x2d, 0x73, 0x68,
+ 0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, 0x00,
+ 0x00, 0x00, 0x08, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, 0x00,
+ 0x00, 0x00, 0x41, 0x04, 0x0a, 0x00, 0x6c, 0x7c, 0x1c, 0xc4, 0x03, 0x44,
+ 0x46, 0x70, 0xba, 0x00, 0x7c, 0x79, 0x89, 0x7b, 0xc3, 0xd6, 0x32, 0x98,
+ 0x34, 0xe7, 0x1c, 0x60, 0x04, 0x73, 0xd9, 0xb5, 0x7e, 0x94, 0x04, 0x04,
+ 0xea, 0xc8, 0xb8, 0xfb, 0xd4, 0x70, 0x9f, 0x29, 0xa7, 0x8d, 0x9a, 0x64,
+ 0x3a, 0x8c, 0x45, 0x23, 0x37, 0x5a, 0x2b, 0x4f, 0x54, 0x91, 0x80, 0xf1,
+ 0xac, 0x3a, 0xf5, 0x6d, 0xfa, 0xe8, 0x76, 0x20, 0x00, 0x00, 0x00, 0x21,
+ 0x00, 0xc2, 0xaf, 0xbe, 0xdc, 0x06, 0xff, 0x3d, 0x08, 0x9b, 0x73, 0xe0,
+ 0x3c, 0x58, 0x28, 0x70, 0x9b, 0x23, 0x39, 0x51, 0xd7, 0xbc, 0xa7, 0x1a,
+ 0xf5, 0xb4, 0x23, 0xd3, 0xf6, 0x17, 0xa6, 0x9c, 0x02
+};
+static unsigned int keye_len = 141;
+static unsigned char keyd[] = {
+ 0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x64, 0x73, 0x73, 0x00,
+ 0x00, 0x00, 0x81, 0x00, 0xb0, 0x02, 0x19, 0x8b, 0xf3, 0x46, 0xf9, 0xc5,
+ 0x47, 0x78, 0x3d, 0x7f, 0x04, 0x10, 0x0a, 0x43, 0x8e, 0x00, 0x9e, 0xa4,
+ 0x30, 0xfd, 0x47, 0xb9, 0x05, 0x9e, 0x95, 0xaa, 0x37, 0x9a, 0x91, 0xbf,
+ 0xf8, 0xb9, 0xe0, 0x8d, 0x97, 0x49, 0x87, 0xe2, 0xe6, 0x90, 0xc1, 0xe4,
+ 0x61, 0x57, 0x77, 0xfd, 0x91, 0x1d, 0xe1, 0x4b, 0xa0, 0xb2, 0xbc, 0xa1,
+ 0x6a, 0x6a, 0xdd, 0x31, 0xda, 0xe7, 0x54, 0x03, 0xfd, 0x48, 0x62, 0x8a,
+ 0x1d, 0x1d, 0xe2, 0x26, 0x76, 0x29, 0x08, 0xab, 0x65, 0x88, 0x74, 0x02,
+ 0x1e, 0xa9, 0x29, 0x1b, 0x69, 0x3b, 0xb4, 0x5f, 0x62, 0x80, 0xa3, 0xa6,
+ 0x4b, 0xc3, 0x0e, 0x89, 0x24, 0xe4, 0x8a, 0x31, 0xae, 0x89, 0x7a, 0x7a,
+ 0x58, 0x44, 0x46, 0x77, 0x62, 0x33, 0xa2, 0x5d, 0x17, 0x0e, 0x0b, 0x64,
+ 0xee, 0x1a, 0x02, 0xbd, 0xf8, 0x27, 0x86, 0xe1, 0x87, 0x92, 0x84, 0xc7,
+ 0x00, 0x00, 0x00, 0x15, 0x00, 0xb3, 0x8b, 0x81, 0x39, 0x9c, 0xba, 0xe1,
+ 0x1d, 0x9a, 0x8b, 0x89, 0xb3, 0x08, 0x9b, 0x12, 0xa8, 0x7b, 0xea, 0x25,
+ 0x8d, 0x00, 0x00, 0x00, 0x80, 0x76, 0x3f, 0x72, 0xb2, 0xef, 0xc3, 0x16,
+ 0xd8, 0x09, 0x36, 0x23, 0x03, 0xf9, 0x5c, 0xac, 0x8b, 0x51, 0x35, 0x2e,
+ 0x36, 0xba, 0x39, 0xd0, 0x57, 0x19, 0x4f, 0x14, 0x8b, 0xea, 0x32, 0xfc,
+ 0x86, 0x41, 0xea, 0x85, 0x71, 0x4d, 0x52, 0x0c, 0xff, 0xc1, 0xd3, 0xd5,
+ 0xcd, 0x2e, 0x37, 0xcc, 0xe1, 0xcc, 0x22, 0x38, 0xa8, 0x47, 0x16, 0x34,
+ 0x3b, 0x32, 0x9c, 0x2f, 0x0f, 0xcd, 0x5f, 0x7f, 0x06, 0x64, 0x89, 0xc5,
+ 0x02, 0x4f, 0x9a, 0x70, 0x11, 0xf0, 0xaa, 0xe1, 0x7a, 0x75, 0x49, 0x8d,
+ 0x0f, 0x8d, 0x5b, 0x54, 0xe2, 0xe7, 0x10, 0x6e, 0xe5, 0xbd, 0xb7, 0x62,
+ 0xf7, 0x40, 0x59, 0x39, 0x31, 0xd9, 0x13, 0x7b, 0xa3, 0xdf, 0x0d, 0x31,
+ 0x52, 0x43, 0xe0, 0xaf, 0x19, 0x12, 0x15, 0x12, 0x34, 0x01, 0x6f, 0xcf,
+ 0x62, 0x21, 0xe4, 0xc8, 0x34, 0x69, 0xc9, 0x85, 0xe3, 0xde, 0xd7, 0x0c,
+ 0xac, 0x00, 0x00, 0x00, 0x80, 0x41, 0xa3, 0xc5, 0xa4, 0x89, 0x86, 0xc8,
+ 0x17, 0xf3, 0x8e, 0x68, 0x72, 0xbe, 0x13, 0x8b, 0x63, 0xe3, 0x07, 0xe3,
+ 0xd5, 0xa4, 0xa2, 0xd3, 0x2c, 0x2f, 0xbe, 0x16, 0x71, 0xc9, 0x79, 0x64,
+ 0x5a, 0x1e, 0x19, 0x82, 0x07, 0xe2, 0x93, 0xda, 0x22, 0xcf, 0x6d, 0xdd,
+ 0x38, 0xcb, 0x6e, 0x6b, 0x0f, 0x95, 0x8d, 0xfa, 0x3f, 0xbb, 0xb8, 0x6a,
+ 0x7d, 0xc3, 0x22, 0x1e, 0x49, 0xcf, 0x98, 0x73, 0x05, 0x5d, 0x97, 0xfa,
+ 0x4c, 0xf2, 0x82, 0x3d, 0x98, 0x61, 0x4e, 0x96, 0x80, 0x26, 0x79, 0xda,
+ 0x24, 0xf8, 0xa1, 0x9c, 0x71, 0x82, 0xe6, 0xc7, 0xdc, 0xc2, 0xa5, 0xd0,
+ 0xf4, 0x36, 0xba, 0xaa, 0xee, 0xd3, 0x43, 0x46, 0x1d, 0xaa, 0x53, 0xea,
+ 0x85, 0x2c, 0x1b, 0xc8, 0x7c, 0x3c, 0xe7, 0x06, 0x44, 0xab, 0x16, 0xad,
+ 0xc6, 0x54, 0x91, 0x9a, 0xb9, 0xc0, 0xeb, 0x93, 0x8c, 0xca, 0x39, 0xcf,
+ 0x6f, 0x00, 0x00, 0x00, 0x15, 0x00, 0x90, 0x26, 0x0a, 0xfc, 0x15, 0x99,
+ 0x7b, 0xac, 0xaa, 0x0c, 0xa2, 0xca, 0x7b, 0xa8, 0xd4, 0xdf, 0x68, 0x56,
+ 0xf9, 0x39
+};
+static unsigned int keyd_len = 458;
+static unsigned char keyed25519[] = {
+ 0x00, 0x00, 0x00, 0x0b, 0x73, 0x73, 0x68, 0x2d, 0x65, 0x64, 0x32, 0x35,
+ 0x35, 0x31, 0x39, 0x00, 0x00, 0x00, 0x40, 0x10, 0xb3, 0x79, 0x06, 0xe5,
+ 0x9b, 0xe7, 0xe4, 0x6e, 0xec, 0xfe, 0xa5, 0x39, 0x21, 0x7c, 0xf6, 0x66,
+ 0x8c, 0x0b, 0x6a, 0x01, 0x09, 0x05, 0xc7, 0x4f, 0x64, 0xa8, 0x24, 0xd2,
+ 0x8d, 0xbd, 0xdd, 0xc6, 0x3c, 0x99, 0x1b, 0x2d, 0x3e, 0x33, 0x90, 0x19,
+ 0xa4, 0xd5, 0xe9, 0x23, 0xfe, 0x8e, 0xd6, 0xd4, 0xf9, 0xb1, 0x11, 0x69,
+ 0x7c, 0x57, 0x52, 0x0e, 0x41, 0xdb, 0x1b, 0x12, 0x87, 0xfa, 0xc9
+};
+static unsigned int keyed25519_len = 83;
diff --git a/fuzz/fuzz-wrapfd.c b/fuzz/fuzz-wrapfd.c
new file mode 100644
index 0000000..c6d59fc
--- /dev/null
+++ b/fuzz/fuzz-wrapfd.c
@@ -0,0 +1,241 @@
+#define FUZZ_SKIP_WRAP 1
+#include "includes.h"
+#include "fuzz-wrapfd.h"
+
+#include "dbutil.h"
+
+#include "fuzz.h"
+
+#define IOWRAP_MAXFD (FD_SETSIZE-1)
+static const int MAX_RANDOM_IN = 50000;
+static const double CHANCE_CLOSE = 1.0 / 600;
+static const double CHANCE_INTR = 1.0 / 900;
+static const double CHANCE_READ1 = 0.96;
+static const double CHANCE_READ2 = 0.5;
+static const double CHANCE_WRITE1 = 0.96;
+static const double CHANCE_WRITE2 = 0.5;
+
+struct fdwrap {
+ enum wrapfd_mode mode;
+ int closein;
+ int closeout;
+};
+
+static struct fdwrap wrap_fds[IOWRAP_MAXFD+1] = {{UNUSED, 0, 0}};
+static int wrapfd_maxfd = -1;
+static unsigned short rand_state[3];
+static buffer *input_buf;
+static int devnull_fd = -1;
+
+static void wrapfd_remove(int fd);
+
+void wrapfd_setup(buffer *buf) {
+ TRACE(("wrapfd_setup"))
+
+ // clean old ones
+ int i;
+ for (i = 0; i <= wrapfd_maxfd; i++) {
+ if (wrap_fds[i].mode == COMMONBUF) {
+ wrapfd_remove(i);
+ }
+ }
+ wrapfd_maxfd = -1;
+
+ memset(rand_state, 0x0, sizeof(rand_state));
+ wrapfd_setseed(50);
+ input_buf = buf;
+}
+
+void wrapfd_setseed(uint32_t seed) {
+ memcpy(rand_state, &seed, sizeof(seed));
+ nrand48(rand_state);
+}
+
+int wrapfd_new() {
+ if (devnull_fd == -1) {
+ devnull_fd = open("/dev/null", O_RDONLY);
+ assert(devnull_fd != -1);
+ }
+
+ int fd = dup(devnull_fd);
+ assert(fd != -1);
+ assert(wrap_fds[fd].mode == UNUSED);
+ wrap_fds[fd].mode = COMMONBUF;
+ wrap_fds[fd].closein = 0;
+ wrap_fds[fd].closeout = 0;
+ wrapfd_maxfd = MAX(fd, wrapfd_maxfd);
+
+ return fd;
+}
+
+static void wrapfd_remove(int fd) {
+ TRACE(("wrapfd_remove %d", fd))
+ assert(fd >= 0);
+ assert(fd <= IOWRAP_MAXFD);
+ assert(wrap_fds[fd].mode != UNUSED);
+ wrap_fds[fd].mode = UNUSED;
+ m_close(fd);
+}
+
+int wrapfd_close(int fd) {
+ if (fd >= 0 && fd <= IOWRAP_MAXFD && wrap_fds[fd].mode != UNUSED) {
+ wrapfd_remove(fd);
+ return 0;
+ } else {
+ return close(fd);
+ }
+}
+
+int wrapfd_read(int fd, void *out, size_t count) {
+ size_t maxread;
+
+ if (!fuzz.wrapfds) {
+ return read(fd, out, count);
+ }
+
+ if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode == UNUSED) {
+ /* XXX - assertion failure? */
+ TRACE(("Bad read descriptor %d\n", fd))
+ errno = EBADF;
+ return -1;
+ }
+
+ assert(count != 0);
+
+ if (wrap_fds[fd].closein || erand48(rand_state) < CHANCE_CLOSE) {
+ wrap_fds[fd].closein = 1;
+ errno = ECONNRESET;
+ return -1;
+ }
+
+ if (erand48(rand_state) < CHANCE_INTR) {
+ errno = EINTR;
+ return -1;
+ }
+
+ if (input_buf) {
+ maxread = MIN(input_buf->len - input_buf->pos, count);
+ /* returns 0 if buf is EOF, as intended */
+ if (maxread > 0) {
+ maxread = nrand48(rand_state) % maxread + 1;
+ }
+ memcpy(out, buf_getptr(input_buf, maxread), maxread);
+ buf_incrpos(input_buf, maxread);
+ return maxread;
+ }
+
+ maxread = MIN(MAX_RANDOM_IN, count);
+ maxread = nrand48(rand_state) % maxread + 1;
+ memset(out, 0xef, maxread);
+ return maxread;
+}
+
+int wrapfd_write(int fd, const void* in, size_t count) {
+ unsigned const volatile char* volin = in;
+ unsigned int i;
+
+ if (!fuzz.wrapfds) {
+ return write(fd, in, count);
+ }
+
+ if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode == UNUSED) {
+ /* XXX - assertion failure? */
+ TRACE(("Bad read descriptor %d\n", fd))
+ errno = EBADF;
+ return -1;
+ }
+
+ assert(count != 0);
+
+ /* force read to exercise sanitisers */
+ for (i = 0; i < count; i++) {
+ (void)volin[i];
+ }
+
+ if (wrap_fds[fd].closeout || erand48(rand_state) < CHANCE_CLOSE) {
+ wrap_fds[fd].closeout = 1;
+ errno = ECONNRESET;
+ return -1;
+ }
+
+ if (erand48(rand_state) < CHANCE_INTR) {
+ errno = EINTR;
+ return -1;
+ }
+
+ return nrand48(rand_state) % (count+1);
+}
+
+int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout) {
+ int i, nset, sel;
+ int ret = 0;
+ int fdlist[IOWRAP_MAXFD+1];
+
+ if (!fuzz.wrapfds) {
+ return select(nfds, readfds, writefds, exceptfds, timeout);
+ }
+
+ assert(nfds <= IOWRAP_MAXFD+1);
+
+ if (erand48(rand_state) < CHANCE_INTR) {
+ errno = EINTR;
+ return -1;
+ }
+
+ /* read */
+ if (readfds != NULL && erand48(rand_state) < CHANCE_READ1) {
+ for (i = 0, nset = 0; i < nfds; i++) {
+ if (FD_ISSET(i, readfds)) {
+ assert(wrap_fds[i].mode != UNUSED);
+ fdlist[nset] = i;
+ nset++;
+ }
+ }
+ DROPBEAR_FD_ZERO(readfds);
+
+ if (nset > 0) {
+ /* set one */
+ sel = fdlist[nrand48(rand_state) % nset];
+ FD_SET(sel, readfds);
+ ret++;
+
+ if (erand48(rand_state) < CHANCE_READ2) {
+ sel = fdlist[nrand48(rand_state) % nset];
+ if (!FD_ISSET(sel, readfds)) {
+ FD_SET(sel, readfds);
+ ret++;
+ }
+ }
+ }
+ }
+
+ /* write */
+ if (writefds != NULL && erand48(rand_state) < CHANCE_WRITE1) {
+ for (i = 0, nset = 0; i < nfds; i++) {
+ if (FD_ISSET(i, writefds)) {
+ assert(wrap_fds[i].mode != UNUSED);
+ fdlist[nset] = i;
+ nset++;
+ }
+ }
+ DROPBEAR_FD_ZERO(writefds);
+
+ /* set one */
+ if (nset > 0) {
+ sel = fdlist[nrand48(rand_state) % nset];
+ FD_SET(sel, writefds);
+ ret++;
+
+ if (erand48(rand_state) < CHANCE_WRITE2) {
+ sel = fdlist[nrand48(rand_state) % nset];
+ if (!FD_ISSET(sel, writefds)) {
+ FD_SET(sel, writefds);
+ ret++;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
diff --git a/fuzz/fuzzer-client.c b/fuzz/fuzzer-client.c
new file mode 100644
index 0000000..eb59f46
--- /dev/null
+++ b/fuzz/fuzzer-client.c
@@ -0,0 +1,6 @@
+#include "fuzz.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ return fuzz_run_client(Data, Size, 0);
+}
+
diff --git a/fuzz/fuzzer-client_nomaths.c b/fuzz/fuzzer-client_nomaths.c
new file mode 100644
index 0000000..e0910a7
--- /dev/null
+++ b/fuzz/fuzzer-client_nomaths.c
@@ -0,0 +1,6 @@
+#include "fuzz.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ return fuzz_run_client(Data, Size, 1);
+}
+
diff --git a/fuzz/fuzzer-kexcurve25519.c b/fuzz/fuzzer-kexcurve25519.c
new file mode 100644
index 0000000..f2eab14
--- /dev/null
+++ b/fuzz/fuzzer-kexcurve25519.c
@@ -0,0 +1,72 @@
+#include "fuzz.h"
+#include "session.h"
+#include "fuzz-wrapfd.h"
+#include "debug.h"
+#include "runopts.h"
+#include "algo.h"
+#include "bignum.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ static int once = 0;
+ static struct key_context* keep_newkeys = NULL;
+ /* number of generated parameters is limited by the timeout for the first run.
+ TODO move this to the libfuzzer initialiser function instead if the timeout
+ doesn't apply there */
+ #define NUM_PARAMS 20
+ static struct kex_curve25519_param *curve25519_params[NUM_PARAMS];
+
+ if (!once) {
+ fuzz_common_setup();
+ fuzz_svr_setup();
+
+ keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
+ keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "curve25519-sha256");
+ keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ED25519;
+ ses.newkeys = keep_newkeys;
+
+ /* Pre-generate parameters */
+ int i;
+ for (i = 0; i < NUM_PARAMS; i++) {
+ curve25519_params[i] = gen_kexcurve25519_param();
+ }
+
+ once = 1;
+ }
+
+ if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
+ return 0;
+ }
+
+ m_malloc_set_epoch(1);
+
+ if (setjmp(fuzz.jmp) == 0) {
+ /* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply()
+ with DROPBEAR_KEX_CURVE25519 */
+ ses.newkeys = keep_newkeys;
+
+ /* Choose from the collection of curve25519 params */
+ unsigned int e = buf_getint(fuzz.input);
+ struct kex_curve25519_param *curve25519_param = curve25519_params[e % NUM_PARAMS];
+
+ buffer * ecdh_qs = buf_getstringbuf(fuzz.input);
+
+ ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
+ kexcurve25519_comb_key(curve25519_param, ecdh_qs, svr_opts.hostkey);
+
+ mp_clear(ses.dh_K);
+ m_free(ses.dh_K);
+ buf_free(ecdh_qs);
+
+ buf_free(ses.hash);
+ buf_free(ses.session_id);
+ /* kexhashbuf is freed in kexdh_comb_key */
+
+ m_malloc_free_epoch(1, 0);
+ } else {
+ m_malloc_free_epoch(1, 1);
+ TRACE(("dropbear_exit longjmped"))
+ /* dropbear_exit jumped here */
+ }
+
+ return 0;
+}
diff --git a/fuzz/fuzzer-kexdh.c b/fuzz/fuzzer-kexdh.c
new file mode 100644
index 0000000..224ff58
--- /dev/null
+++ b/fuzz/fuzzer-kexdh.c
@@ -0,0 +1,76 @@
+#include "fuzz.h"
+#include "session.h"
+#include "fuzz-wrapfd.h"
+#include "debug.h"
+#include "runopts.h"
+#include "algo.h"
+#include "bignum.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ static int once = 0;
+ static struct key_context* keep_newkeys = NULL;
+ /* number of generated parameters is limited by the timeout for the first run.
+ TODO move this to the libfuzzer initialiser function instead if the timeout
+ doesn't apply there */
+ #define NUM_PARAMS 20
+ static struct kex_dh_param *dh_params[NUM_PARAMS];
+
+ if (!once) {
+ fuzz_common_setup();
+ fuzz_svr_setup();
+
+ keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
+ keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "diffie-hellman-group14-sha256");
+ keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
+ ses.newkeys = keep_newkeys;
+
+ /* Pre-generate parameters */
+ int i;
+ for (i = 0; i < NUM_PARAMS; i++) {
+ dh_params[i] = gen_kexdh_param();
+ }
+
+ once = 1;
+ }
+
+ if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
+ return 0;
+ }
+
+ m_malloc_set_epoch(1);
+
+ if (setjmp(fuzz.jmp) == 0) {
+ /* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply()
+ with DROPBEAR_KEX_NORMAL_DH */
+ ses.newkeys = keep_newkeys;
+
+ /* Choose from the collection of ecdh params */
+ unsigned int e = buf_getint(fuzz.input);
+ struct kex_dh_param * dh_param = dh_params[e % NUM_PARAMS];
+
+ DEF_MP_INT(dh_e);
+ m_mp_init(&dh_e);
+ if (buf_getmpint(fuzz.input, &dh_e) != DROPBEAR_SUCCESS) {
+ dropbear_exit("Bad kex value");
+ }
+
+ ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
+ kexdh_comb_key(dh_param, &dh_e, svr_opts.hostkey);
+
+ mp_clear(ses.dh_K);
+ m_free(ses.dh_K);
+ mp_clear(&dh_e);
+
+ buf_free(ses.hash);
+ buf_free(ses.session_id);
+ /* kexhashbuf is freed in kexdh_comb_key */
+
+ m_malloc_free_epoch(1, 0);
+ } else {
+ m_malloc_free_epoch(1, 1);
+ TRACE(("dropbear_exit longjmped"))
+ /* dropbear_exit jumped here */
+ }
+
+ return 0;
+}
diff --git a/fuzz/fuzzer-kexecdh.c b/fuzz/fuzzer-kexecdh.c
new file mode 100644
index 0000000..c3a450a
--- /dev/null
+++ b/fuzz/fuzzer-kexecdh.c
@@ -0,0 +1,82 @@
+#include "fuzz.h"
+#include "session.h"
+#include "fuzz-wrapfd.h"
+#include "debug.h"
+#include "runopts.h"
+#include "algo.h"
+#include "bignum.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ static int once = 0;
+ static const struct dropbear_kex *ecdh[3]; /* 256, 384, 521 */
+ static struct key_context* keep_newkeys = NULL;
+ /* number of generated parameters is limited by the timeout for the first run */
+ #define NUM_PARAMS 80
+ static struct kex_ecdh_param *ecdh_params[NUM_PARAMS];
+
+ if (!once) {
+ fuzz_common_setup();
+ fuzz_svr_setup();
+
+ /* ses gets zeroed by fuzz_set_input */
+ keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
+ ecdh[0] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp256");
+ ecdh[1] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp384");
+ ecdh[2] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp521");
+ assert(ecdh[0]);
+ assert(ecdh[1]);
+ assert(ecdh[2]);
+ keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
+ ses.newkeys = keep_newkeys;
+
+ /* Pre-generate parameters */
+ int i;
+ for (i = 0; i < NUM_PARAMS; i++) {
+ ses.newkeys->algo_kex = ecdh[i % 3];
+ ecdh_params[i] = gen_kexecdh_param();
+ }
+
+ once = 1;
+ }
+
+ if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
+ return 0;
+ }
+
+ m_malloc_set_epoch(1);
+
+ if (setjmp(fuzz.jmp) == 0) {
+ /* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply()
+ with DROPBEAR_KEX_ECDH */
+ ses.newkeys = keep_newkeys;
+
+ /* random choice of ecdh 256, 384, 521 */
+ unsigned char b = buf_getbyte(fuzz.input);
+ ses.newkeys->algo_kex = ecdh[b % 3];
+
+ /* Choose from the collection of ecdh params */
+ unsigned int e = buf_getint(fuzz.input);
+ struct kex_ecdh_param *ecdh_param = ecdh_params[e % NUM_PARAMS];
+
+ buffer * ecdh_qs = buf_getstringbuf(fuzz.input);
+
+ ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
+ kexecdh_comb_key(ecdh_param, ecdh_qs, svr_opts.hostkey);
+
+ mp_clear(ses.dh_K);
+ m_free(ses.dh_K);
+ buf_free(ecdh_qs);
+
+ buf_free(ses.hash);
+ buf_free(ses.session_id);
+ /* kexhashbuf is freed in kexdh_comb_key */
+
+ m_malloc_free_epoch(1, 0);
+ } else {
+ m_malloc_free_epoch(1, 1);
+ TRACE(("dropbear_exit longjmped"))
+ /* dropbear_exit jumped here */
+ }
+
+ return 0;
+}
diff --git a/fuzz/fuzzer-preauth.c b/fuzz/fuzzer-preauth.c
new file mode 100644
index 0000000..3ac49f4
--- /dev/null
+++ b/fuzz/fuzzer-preauth.c
@@ -0,0 +1,6 @@
+#include "fuzz.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ return fuzz_run_preauth(Data, Size, 0);
+}
+
diff --git a/fuzz/fuzzer-preauth_nomaths.c b/fuzz/fuzzer-preauth_nomaths.c
new file mode 100644
index 0000000..efdc2c3
--- /dev/null
+++ b/fuzz/fuzzer-preauth_nomaths.c
@@ -0,0 +1,6 @@
+#include "fuzz.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ return fuzz_run_preauth(Data, Size, 1);
+}
+
diff --git a/fuzz/fuzzer-pubkey.c b/fuzz/fuzzer-pubkey.c
new file mode 100644
index 0000000..7c12cdc
--- /dev/null
+++ b/fuzz/fuzzer-pubkey.c
@@ -0,0 +1,54 @@
+#include "fuzz.h"
+#include "session.h"
+#include "fuzz-wrapfd.h"
+#include "debug.h"
+
+static void setup_fuzzer(void) {
+ fuzz_common_setup();
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ static int once = 0;
+ if (!once) {
+ setup_fuzzer();
+ once = 1;
+ }
+
+ if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
+ return 0;
+ }
+
+ m_malloc_set_epoch(1);
+
+ if (setjmp(fuzz.jmp) == 0) {
+ buffer *line = buf_getstringbuf(fuzz.input);
+ buffer *keyblob = buf_getstringbuf(fuzz.input);
+
+ unsigned int algolen;
+ char* algoname = buf_getstring(keyblob, &algolen);
+
+ if (signature_type_from_name(algoname, algolen) == DROPBEAR_SIGNKEY_NONE) {
+ dropbear_exit("fuzzer imagined a bogus algorithm");
+ }
+
+ int ret = fuzz_checkpubkey_line(line, 5, "/home/me/authorized_keys",
+ algoname, algolen,
+ keyblob->data, keyblob->len);
+
+ if (ret == DROPBEAR_SUCCESS) {
+ /* fuzz_checkpubkey_line() should have cleaned up for failure */
+ svr_pubkey_options_cleanup();
+ }
+
+ buf_free(line);
+ buf_free(keyblob);
+ m_free(algoname);
+ m_malloc_free_epoch(1, 0);
+ } else {
+ m_malloc_free_epoch(1, 1);
+ TRACE(("dropbear_exit longjmped"))
+ /* dropbear_exit jumped here */
+ }
+
+ return 0;
+}
diff --git a/fuzz/fuzzer-verify.c b/fuzz/fuzzer-verify.c
new file mode 100644
index 0000000..a0ad086
--- /dev/null
+++ b/fuzz/fuzzer-verify.c
@@ -0,0 +1,79 @@
+#include "fuzz.h"
+#include "session.h"
+#include "fuzz-wrapfd.h"
+#include "debug.h"
+#include "dss.h"
+
+static void setup_fuzzer(void) {
+ fuzz_common_setup();
+}
+
+static buffer *verifydata;
+
+/* Tests reading a public key and verifying a signature */
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ static int once = 0;
+ if (!once) {
+ setup_fuzzer();
+ verifydata = buf_new(30);
+ buf_putstring(verifydata, "x", 1);
+ once = 1;
+ }
+
+ if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
+ return 0;
+ }
+
+ m_malloc_set_epoch(1);
+
+ if (setjmp(fuzz.jmp) == 0) {
+ sign_key *key = new_sign_key();
+ enum signkey_type keytype = DROPBEAR_SIGNKEY_ANY;
+ if (buf_get_pub_key(fuzz.input, key, &keytype) == DROPBEAR_SUCCESS) {
+ enum signature_type sigtype;
+ if (keytype == DROPBEAR_SIGNKEY_RSA) {
+ /* Flip a coin to decide rsa signature type */
+ int flag = buf_getbyte(fuzz.input);
+ if (flag & 0x01) {
+ sigtype = DROPBEAR_SIGNATURE_RSA_SHA256;
+ } else {
+ sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
+ }
+ } else {
+ sigtype = signature_type_from_signkey(keytype);
+ }
+ if (buf_verify(fuzz.input, key, sigtype, verifydata) == DROPBEAR_SUCCESS) {
+ /* The fuzzer is capable of generating keys with a signature to match.
+ We don't want false positives if the key is bogus, since a client/server
+ wouldn't be trusting a bogus key anyway */
+ int boguskey = 0;
+
+ if (keytype == DROPBEAR_SIGNKEY_DSS) {
+ /* So far have seen dss keys with bad p/q/g domain parameters */
+ int pprime, qprime, trials;
+ trials = mp_prime_rabin_miller_trials(mp_count_bits(key->dsskey->p));
+ assert(mp_prime_is_prime(key->dsskey->p, trials, &pprime) == MP_OKAY);
+ trials = mp_prime_rabin_miller_trials(mp_count_bits(key->dsskey->q));
+ assert(mp_prime_is_prime(key->dsskey->q, trials, &qprime) == MP_OKAY);
+ boguskey = !(pprime && qprime);
+ /* Could also check g**q mod p == 1 */
+ }
+
+ if (!boguskey) {
+ printf("Random key/signature managed to verify!\n");
+ abort();
+ }
+
+
+ }
+ }
+ sign_key_free(key);
+ m_malloc_free_epoch(1, 0);
+ } else {
+ m_malloc_free_epoch(1, 1);
+ TRACE(("dropbear_exit longjmped"))
+ /* dropbear_exit jumped here */
+ }
+
+ return 0;
+}