aboutsummaryrefslogtreecommitdiff
path: root/regress/misc
diff options
context:
space:
mode:
Diffstat (limited to 'regress/misc')
-rw-r--r--regress/misc/Makefile2
-rw-r--r--regress/misc/fuzz-harness/Makefile46
-rw-r--r--regress/misc/fuzz-harness/agent_fuzz.cc15
-rw-r--r--regress/misc/fuzz-harness/agent_fuzz_helper.c177
-rw-r--r--regress/misc/fuzz-harness/fixed-keys.h119
-rw-r--r--regress/misc/fuzz-harness/kex_fuzz.cc461
-rw-r--r--regress/misc/fuzz-harness/testdata/README4
-rwxr-xr-xregress/misc/fuzz-harness/testdata/create-agent-corpus.sh44
-rw-r--r--regress/misc/fuzz-harness/testdata/id_dsa21
-rw-r--r--regress/misc/fuzz-harness/testdata/id_dsa-cert.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_dsa.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ecdsa8
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ecdsa-cert.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ecdsa.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ecdsa_sk14
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ecdsa_sk-cert.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ecdsa_sk.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ed255197
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ed25519-cert.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ed25519.pub2
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ed25519_sk8
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ed25519_sk-cert.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ed25519_sk.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_rsa27
-rw-r--r--regress/misc/fuzz-harness/testdata/id_rsa-cert.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_rsa.pub1
-rw-r--r--regress/misc/kexfuzz/Makefile101
-rw-r--r--regress/misc/kexfuzz/README34
-rw-r--r--regress/misc/kexfuzz/kexfuzz.c453
-rw-r--r--regress/misc/sk-dummy/fatal.c11
-rw-r--r--regress/misc/sk-dummy/sk-dummy.c7
31 files changed, 965 insertions, 607 deletions
diff --git a/regress/misc/Makefile b/regress/misc/Makefile
index cf95f265ce47..b9149f2879eb 100644
--- a/regress/misc/Makefile
+++ b/regress/misc/Makefile
@@ -1,3 +1,3 @@
-SUBDIR= kexfuzz sk-dummy
+SUBDIR= sk-dummy
.include <bsd.subdir.mk>
diff --git a/regress/misc/fuzz-harness/Makefile b/regress/misc/fuzz-harness/Makefile
index 64fbdbab162b..e879fcdae297 100644
--- a/regress/misc/fuzz-harness/Makefile
+++ b/regress/misc/fuzz-harness/Makefile
@@ -1,38 +1,52 @@
# NB. libssh and libopenbsd-compat should be built with the same sanitizer opts.
-CXX=clang++-6.0
-FUZZ_FLAGS=-fsanitize=address,undefined -fsanitize-coverage=edge,trace-pc
+CC=clang-11
+CXX=clang++-11
+FUZZ_FLAGS=-fsanitize=address,fuzzer -fno-omit-frame-pointer
FUZZ_LIBS=-lFuzzer
CXXFLAGS=-O2 -g -Wall -Wextra -Wno-unused-parameter -I ../../.. $(FUZZ_FLAGS)
+CFLAGS=$(CXXFLAGS)
LDFLAGS=-L ../../.. -L ../../../openbsd-compat -g $(FUZZ_FLAGS)
LIBS=-lssh -lopenbsd-compat -lcrypto -lfido2 -lcbor $(FUZZ_LIBS)
-COMMON_OBJS=ssh-sk-null.o
+SK_NULL_OBJS=ssh-sk-null.o
+COMMON_DEPS=../../../libssh.a
TARGETS=pubkey_fuzz sig_fuzz authopt_fuzz sshsig_fuzz \
- sshsigopt_fuzz privkey_fuzz
+ sshsigopt_fuzz privkey_fuzz kex_fuzz agent_fuzz
all: $(TARGETS)
.cc.o:
$(CXX) $(CXXFLAGS) -c $< -o $@
-pubkey_fuzz: pubkey_fuzz.o $(COMMON_OBJS)
- $(CXX) -o $@ pubkey_fuzz.o $(COMMON_OBJS) $(LDFLAGS) $(LIBS)
+pubkey_fuzz: pubkey_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
+ $(CXX) -o $@ pubkey_fuzz.o $(SK_NULL_OBJS) $(LDFLAGS) $(LIBS)
-sig_fuzz: sig_fuzz.o $(COMMON_OBJS)
- $(CXX) -o $@ sig_fuzz.o $(COMMON_OBJS) $(LDFLAGS) $(LIBS)
+sig_fuzz: sig_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
+ $(CXX) -o $@ sig_fuzz.o $(SK_NULL_OBJS) $(LDFLAGS) $(LIBS)
-authopt_fuzz: authopt_fuzz.o $(COMMON_OBJS)
- $(CXX) -o $@ authopt_fuzz.o $(COMMON_OBJS) ../../../auth-options.o $(LDFLAGS) $(LIBS)
+authopt_fuzz: authopt_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
+ $(CXX) -o $@ authopt_fuzz.o $(SK_NULL_OBJS) ../../../auth-options.o $(LDFLAGS) $(LIBS)
-sshsig_fuzz: sshsig_fuzz.o $(COMMON_OBJS)
- $(CXX) -o $@ sshsig_fuzz.o $(COMMON_OBJS) ../../../sshsig.o $(LDFLAGS) $(LIBS)
+sshsig_fuzz: sshsig_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
+ $(CXX) -o $@ sshsig_fuzz.o $(SK_NULL_OBJS) ../../../sshsig.o $(LDFLAGS) $(LIBS)
-sshsigopt_fuzz: sshsigopt_fuzz.o $(COMMON_OBJS)
- $(CXX) -o $@ sshsigopt_fuzz.o $(COMMON_OBJS) ../../../sshsig.o $(LDFLAGS) $(LIBS)
+sshsigopt_fuzz: sshsigopt_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
+ $(CXX) -o $@ sshsigopt_fuzz.o $(SK_NULL_OBJS) ../../../sshsig.o $(LDFLAGS) $(LIBS)
-privkey_fuzz: privkey_fuzz.o $(COMMON_OBJS)
- $(CXX) -o $@ privkey_fuzz.o $(COMMON_OBJS) $(LDFLAGS) $(LIBS)
+privkey_fuzz: privkey_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
+ $(CXX) -o $@ privkey_fuzz.o $(SK_NULL_OBJS) $(LDFLAGS) $(LIBS)
+
+kex_fuzz: kex_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
+ $(CXX) -o $@ kex_fuzz.o $(SK_NULL_OBJS) $(LDFLAGS) $(LIBS) -lz
+
+agent_fuzz: agent_fuzz.o agent_fuzz_helper.o sk-dummy.o ../../../ssh-sk.o $(COMMON_DEPS)
+ $(CXX) -o $@ agent_fuzz.o agent_fuzz_helper.o sk-dummy.o ../../../ssh-sk.o $(LDFLAGS) $(LIBS) -lz
+
+agent_fuzz_helper.o: agent_fuzz_helper.c ../../../ssh-agent.c
+
+sk-dummy.o: ../sk-dummy/sk-dummy.c
+ $(CC) $(CFLAGS) -c -o $@ ../sk-dummy/sk-dummy.c -DSK_DUMMY_INTEGRATE=1 $(LDFLAGS)
clean:
-rm -f *.o $(TARGETS)
diff --git a/regress/misc/fuzz-harness/agent_fuzz.cc b/regress/misc/fuzz-harness/agent_fuzz.cc
new file mode 100644
index 000000000000..ad85b2f9a297
--- /dev/null
+++ b/regress/misc/fuzz-harness/agent_fuzz.cc
@@ -0,0 +1,15 @@
+// cc_fuzz_target test for ssh-agent.
+extern "C" {
+
+#include <stdint.h>
+#include <sys/types.h>
+
+extern void test_one(const uint8_t* s, size_t slen);
+
+int LLVMFuzzerTestOneInput(const uint8_t* s, size_t slen)
+{
+ test_one(s, slen);
+ return 0;
+}
+
+} // extern
diff --git a/regress/misc/fuzz-harness/agent_fuzz_helper.c b/regress/misc/fuzz-harness/agent_fuzz_helper.c
new file mode 100644
index 000000000000..1d419820cc5d
--- /dev/null
+++ b/regress/misc/fuzz-harness/agent_fuzz_helper.c
@@ -0,0 +1,177 @@
+#include "fixed-keys.h"
+#include <assert.h>
+
+#define main(ac, av) xxxmain(ac, av)
+#include "../../../ssh-agent.c"
+
+void test_one(const uint8_t* s, size_t slen);
+
+static int
+devnull_or_die(void)
+{
+ int fd;
+
+ if ((fd = open("/dev/null", O_RDWR)) == -1) {
+ error_f("open /dev/null: %s", strerror(errno));
+ abort();
+ }
+ return fd;
+}
+
+static struct sshkey *
+pubkey_or_die(const char *s)
+{
+ char *tmp, *cp;
+ struct sshkey *pubkey;
+ int r;
+
+ tmp = cp = xstrdup(s);
+ if ((pubkey = sshkey_new(KEY_UNSPEC)) == NULL)
+ abort();
+ if ((r = sshkey_read(pubkey, &cp)) != 0) {
+ error_fr(r, "parse");
+ abort();
+ }
+ free(tmp);
+ return pubkey;
+}
+
+static struct sshkey *
+privkey_or_die(const char *s)
+{
+ int r;
+ struct sshbuf *b;
+ struct sshkey *privkey;
+
+ if ((b = sshbuf_from(s, strlen(s))) == NULL) {
+ error_f("sshbuf_from failed");
+ abort();
+ }
+ if ((r = sshkey_parse_private_fileblob(b, "", &privkey, NULL)) != 0) {
+ error_fr(r, "parse");
+ abort();
+ }
+ sshbuf_free(b);
+ return privkey;
+}
+
+static void
+add_key(const char *privkey, const char *certpath)
+{
+ Identity *id;
+ int r;
+ struct sshkey *cert;
+
+ id = xcalloc(1, sizeof(Identity));
+ TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
+ idtab->nentries++;
+ id->key = privkey_or_die(privkey);
+ id->comment = xstrdup("rhododaktulos Eos");
+ if (sshkey_is_sk(id->key))
+ id->sk_provider = xstrdup("internal");
+
+ /* Now the cert too */
+ id = xcalloc(1, sizeof(Identity));
+ TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
+ idtab->nentries++;
+ id->key = privkey_or_die(privkey);
+ cert = pubkey_or_die(certpath);
+ if ((r = sshkey_to_certified(id->key)) != 0) {
+ error_fr(r, "sshkey_to_certified");
+ abort();
+ }
+ if ((r = sshkey_cert_copy(cert, id->key)) != 0) {
+ error_fr(r, "sshkey_cert_copy");
+ abort();
+ }
+ sshkey_free(cert);
+ id->comment = xstrdup("outis");
+ if (sshkey_is_sk(id->key))
+ id->sk_provider = xstrdup("internal");
+}
+
+static void
+cleanup_idtab(void)
+{
+ Identity *id;
+
+ if (idtab == NULL) return;
+ for (id = TAILQ_FIRST(&idtab->idlist); id;
+ id = TAILQ_FIRST(&idtab->idlist)) {
+ TAILQ_REMOVE(&idtab->idlist, id, next);
+ free_identity(id);
+ }
+ free(idtab);
+ idtab = NULL;
+}
+
+static void
+reset_idtab(void)
+{
+ cleanup_idtab();
+ idtab_init();
+ // Load keys.
+ add_key(PRIV_RSA, CERT_RSA);
+ add_key(PRIV_DSA, CERT_DSA);
+ add_key(PRIV_ECDSA, CERT_ECDSA);
+ add_key(PRIV_ED25519, CERT_ED25519);
+ add_key(PRIV_ECDSA_SK, CERT_ECDSA_SK);
+ add_key(PRIV_ED25519_SK, CERT_ED25519_SK);
+}
+
+static void
+cleanup_sockettab(void)
+{
+ u_int i;
+ for (i = 0; i < sockets_alloc; i++) {
+ if (sockets[i].type != AUTH_UNUSED)
+ close_socket(sockets + i);
+ }
+ free(sockets);
+ sockets = NULL;
+ sockets_alloc = 0;
+}
+
+static void
+reset_sockettab(int devnull)
+{
+ int fd;
+
+ cleanup_sockettab();
+ if ((fd = dup(devnull)) == -1) {
+ error_f("dup: %s", strerror(errno));
+ abort();
+ }
+ new_socket(AUTH_CONNECTION, fd);
+ assert(sockets[0].type == AUTH_CONNECTION);
+ assert(sockets[0].fd == fd);
+}
+
+#define MAX_MESSAGES 256
+void
+test_one(const uint8_t* s, size_t slen)
+{
+ static int devnull = -1;
+ size_t i, olen, nlen;
+
+ if (devnull == -1) {
+ log_init(__progname, SYSLOG_LEVEL_DEBUG3,
+ SYSLOG_FACILITY_AUTH, 1);
+ devnull = devnull_or_die();
+ allowed_providers = xstrdup("");
+ setenv("DISPLAY", "", 1); /* ban askpass */
+ }
+
+ reset_idtab();
+ reset_sockettab(devnull);
+ (void)sshbuf_put(sockets[0].input, s, slen);
+ for (i = 0; i < MAX_MESSAGES; i++) {
+ olen = sshbuf_len(sockets[0].input);
+ process_message(0);
+ nlen = sshbuf_len(sockets[0].input);
+ if (nlen == 0 || nlen == olen)
+ break;
+ }
+ cleanup_idtab();
+ cleanup_sockettab();
+}
diff --git a/regress/misc/fuzz-harness/fixed-keys.h b/regress/misc/fuzz-harness/fixed-keys.h
new file mode 100644
index 000000000000..c6e7c6cc1828
--- /dev/null
+++ b/regress/misc/fuzz-harness/fixed-keys.h
@@ -0,0 +1,119 @@
+/*
+ * Some keys used by fuzzers
+ */
+
+#define PRIV_RSA \
+"-----BEGIN OPENSSH PRIVATE KEY-----\n"\
+"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn\n"\
+"NhAAAAAwEAAQAAAQEA3+epf+VGKoGPaAZXrf6S0cyumQnddkGBnVFX0A5eh37RtLug0qY5\n"\
+"thxsBUbGGVr9mTd2QXwLujBwYg5l1MP/Fmg+5312Zgx9pHmS+qKULbar0hlNgptNEb+aNU\n"\
+"d3o9qg3aXqXm7+ZnjAV05ef/mxNRN2ZvuEkw7cRppTJcbBI+vF3lXuCXnX2klDI95Gl2AW\n"\
+"3WHRtanqLHZXuBkjjRBDKc7MUq/GP1hmLiAd95dvU7fZjRlIEsP84zGEI1Fb0L/kmPHcOt\n"\
+"iVfHft8CtmC9v6+94JrOiPBBNScV+dyrgAGPsdKdr/1vIpQmCNiI8s3PCiD8J7ZiBaYm0I\n"\
+"8fq5G/qnUwAAA7ggw2dXIMNnVwAAAAdzc2gtcnNhAAABAQDf56l/5UYqgY9oBlet/pLRzK\n"\
+"6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZm\n"\
+"DH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGml\n"\
+"MlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29T\n"\
+"t9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v\n"\
+"/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdTAAAAAwEAAQAAAQEArWm5B4tFasppjUHM\n"\
+"SsAuajtCxtizI1Hc10EW59cZM4vvUzE2f6+qZvdgWj3UU/L7Et23w0QVuSCnCerox379ZB\n"\
+"ddEOFFAAiQjwBx65hbd4RRUymxtIQfjq18++LcMJW1nbVQ7c69ThQbtALIggmbS+ZE/8Gx\n"\
+"jkwmIrCH0Ww8TlpsPe+mNHuyNk7UEZoXLm22lNLqq5qkIL5JgT6M2iNJpMOJy9/CKi6kO4\n"\
+"JPuVwjdG4C5pBPaMN3KJ1IvAlSlLGNaXnfXcn85gWfsCjsZmH3liey2NJamqp/w83BrKUg\n"\
+"YZvMR2qeWZaKkFTahpzN5KRK1BFeB37O0P84Dzh1biDX8QAAAIEAiWXW8ePYFwLpa2mFIh\n"\
+"VvRTdcrN70rVK5eWVaL3pyS4vGA56Jixq86dHveOnbSY+iNb1jQidtXc8SWUt2wtHqZ32h\n"\
+"Lji9/hMSKqe9SEP3xvDRDmUJqsVw0ySyrFrzm4160QY6RKU3CIQCVFslMZ9fxmrfZ/hxoU\n"\
+"0X3FVsxmC4+kwAAACBAPOc1YERpV6PjANBrGR+1o1RCdACbm5myc42QzSNIaOZmgrYs+Gt\n"\
+"7+EcoqSdbJzHJNCNQfF+A+vjbIkFiuZqq/5wwr59qXx5OAlijLB/ywwKmTWq6lp//Zxny+\n"\
+"ka3sIGNO14eQvmxNDnlLL+RIZleCTEKBXSW6CZhr+uHMZFKKMtAAAAgQDrSkm+LbILB7H9\n"\
+"jxEBZLhv53aAn4u81kFKQOJ7PzzpBGSoD12i7oIJu5siSD5EKDNVEr+SvCf0ISU3BuMpzl\n"\
+"t3YrPrHRheOFhn5e3j0e//zB8rBC0DGB4CtTDdeh7rOXUL4K0pz+8wEpNkV62SWxhC6NRW\n"\
+"I79JhtGkh+GtcnkEfwAAAAAB\n"\
+"-----END OPENSSH PRIVATE KEY-----\n"
+#define PUB_RSA \
+"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDf56l/5UYqgY9oBlet/pLRzK6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZmDH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGmlMlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29Tt9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdT"
+#define CERT_RSA \
+"ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAg89JX6OBMYDSxER8fnU5y8xxeMCHR/hI0uVqdEhNyCpcAAAADAQABAAABAQDf56l/5UYqgY9oBlet/pLRzK6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZmDH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGmlMlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29Tt9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdTAAAAAAAAA+0AAAABAAAAB3VseXNzZXMAAAAXAAAAB3VseXNzZXMAAAAIb2R5c3NldXMAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgM9BeYRUxUuZ4VHJp8oxVaA8OS/z+5EFPCZwQNq1nMwMAAABTAAAAC3NzaC1lZDI1NTE5AAAAQGCDA6PWw4x9bHQl0w7NqifHepumqD3dmyMx+hZGuPRon+TsyCjfytu7hWmV7l9XUF0fPQNFQ7FGat5e+7YUNgE= id_rsa.pub"
+#define PRIV_DSA \
+"-----BEGIN OPENSSH PRIVATE KEY-----\n"\
+"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsgAAAAdzc2gtZH\n"\
+"NzAAAAgQCsGTfjpQ465EOkfQXJM9BOvfRQE0fqlykAls+ncz+T7hrbeScRu8xpwzsznJNm\n"\
+"xlW8o6cUDiHmBJ5OHgamUC9N7YJeU/6fnOAZifgN8mqK6k8pKHuje8ANOiYgHLl0yiASQA\n"\
+"3//qMyzZ+W/hemoLSmLAbEqlfWVeyYx+wta1Vm+QAAABUAvWyehvUvdHvQxavYgS5p0t5Q\n"\
+"d7UAAACBAIRA9Yy+f4Kzqpv/qICPO3zk42UuP7WAhSW2nCbQdLlCiSTxcjKgcvXNRckwJP\n"\
+"44JjSHOtJy/AMtJrPIbLYG6KuWTdBlEHFiG6DafvLG+qPMSL2bPjXTOhuOMbCHIZ+5WBkW\n"\
+"THeG/Nv11iI01Of9V6tXkig23K370flkRkXFi9MdAAAAgCt6YUcQkNwG7B/e5M1FZsLP9O\n"\
+"kVB3BwLAOjmWdHpyhu3HpwSJa3XLEvhXN0i6IVI2KgPo/2GtYA6rHt14L+6u1pmhh8sAvQ\n"\
+"ksp3qZB+xh/NP+hBqf0sbHX0yYbzKOvI5SCc/kKK6yagcBZOsubM/KC8TxyVgmD5c6WzYs\n"\
+"h5TEpvAAAB2PHjRbbx40W2AAAAB3NzaC1kc3MAAACBAKwZN+OlDjrkQ6R9Bckz0E699FAT\n"\
+"R+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4B\n"\
+"mJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1r\n"\
+"VWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS\n"\
+"4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIb\n"\
+"oNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRc\n"\
+"WL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SL\n"\
+"ohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJ\n"\
+"z+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8AAAAUUA+OGldMi76ClO/sstpdbBUE\n"\
+"lq8AAAAAAQI=\n"\
+"-----END OPENSSH PRIVATE KEY-----\n"
+#define PUB_DSA \
+"ssh-dss AAAAB3NzaC1kc3MAAACBAKwZN+OlDjrkQ6R9Bckz0E699FATR+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4BmJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1rVWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIboNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRcWL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SLohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJz+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8="
+#define CERT_DSA \
+"ssh-dss-cert-v01@openssh.com AAAAHHNzaC1kc3MtY2VydC12MDFAb3BlbnNzaC5jb20AAAAguF716Yub+vVKNlONKLsfxGYWkRe/PyjfYdGRTsFaDvAAAACBAKwZN+OlDjrkQ6R9Bckz0E699FATR+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4BmJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1rVWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIboNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRcWL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SLohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJz+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8AAAAAAAAD6AAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAjMQEZcbdUYJBjIC4GxByFDOb8tv71vDZdx7irHwaqIjx5rzpJUuOV1r8ZO4kY+Yaiun1yrWj2QYkfJrHBvD1DA== id_dsa.pub"
+#define PRIV_ECDSA \
+"-----BEGIN OPENSSH PRIVATE KEY-----\n"\
+"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS\n"\
+"1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTDJ0VlMv+0rguNzaJ1DF2KueHaxRSQ\n"\
+"6LpIxGbulrg1a8RPbnMXwag5GcDiDllD2lDUJUuBEWyjXA0rZoZX35ELAAAAoE/Bbr5PwW\n"\
+"6+AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43N\n"\
+"onUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQ\n"\
+"sAAAAhAIhE6hCID5oOm1TDktc++KFKyScjLifcZ6Cgv5xSSyLOAAAAAAECAwQFBgc=\n"\
+"-----END OPENSSH PRIVATE KEY-----\n"
+#define PUB_ECDSA \
+"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43NonUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQs="
+#define CERT_ECDSA \
+"ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgVJZuM/1AOe6n++qRWMyUuAThYqLvvQxj5CGflLODp60AAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43NonUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQsAAAAAAAAD6QAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAtdJpcF6ZmQL+ueices4QZeL7AK8Xuo08jyLgiolhjKy2jj4LSUki4aX/ZeZeJuby1ovGrfaeFAgx3itPLR7IAQ== id_ecdsa.pub"
+#define PRIV_ED25519 \
+"-----BEGIN OPENSSH PRIVATE KEY-----\n"\
+"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n"\
+"QyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAIhWlP99VpT/\n"\
+"fQAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAw\n"\
+"AAAEDE1rlcMC0s0X3TKVZAOVavZOywwkXw8tO5dLObxaCMEDPQXmEVMVLmeFRyafKMVWgP\n"\
+"Dkv8/uRBTwmcEDatZzMDAAAAAAECAwQF\n"\
+"-----END OPENSSH PRIVATE KEY-----\n"
+#define PUB_ED25519 \
+"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMD"
+#define CERT_ED25519 \
+"ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIMDQjYH6XRzH3j3MW1DdjCoAfvrHfgjnVGF+sLK0pBfqAAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMDAAAAAAAAA+sAAAABAAAAB3VseXNzZXMAAAAXAAAAB3VseXNzZXMAAAAIb2R5c3NldXMAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgM9BeYRUxUuZ4VHJp8oxVaA8OS/z+5EFPCZwQNq1nMwMAAABTAAAAC3NzaC1lZDI1NTE5AAAAQBj0og+s09/HpwdHZbzN0twooKPDWWrxGfnP1Joy6cDnY2BCSQ7zg9vbq11kLF8H/sKOTZWAQrUZ7LlChOu9Ogw= id_ed25519.pub"
+#define PRIV_ECDSA_SK \
+"-----BEGIN OPENSSH PRIVATE KEY-----\n"\
+"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAfwAAACJzay1lY2\n"\
+"RzYS1zaGEyLW5pc3RwMjU2QG9wZW5zc2guY29tAAAACG5pc3RwMjU2AAAAQQTYyU76zop1\n"\
+"VOb4DfKWYnR5b0TOC3zw8DzObAfHWB5o6xls+tOYiEleXvIEi00Da2iCK47habZTOhLyeB\n"\
+"X2Avu5AAAABHNzaDoAAAGYqUAQSKlAEEgAAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBv\n"\
+"cGVuc3NoLmNvbQAAAAhuaXN0cDI1NgAAAEEE2MlO+s6KdVTm+A3ylmJ0eW9Ezgt88PA8zm\n"\
+"wHx1geaOsZbPrTmIhJXl7yBItNA2togiuO4Wm2UzoS8ngV9gL7uQAAAARzc2g6AQAAAOMt\n"\
+"LS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUhjQ0FRRUVJSHFsZjNsWTkxZFhwUn\n"\
+"dYZDBrS0lYWmNpeDRRcDBNSU15Ny9JMUxXSTFuWG9Bb0dDQ3FHU000OQpBd0VIb1VRRFFn\n"\
+"QUUyTWxPK3M2S2RWVG0rQTN5bG1KMGVXOUV6Z3Q4OFBBOHptd0h4MWdlYU9zWmJQclRtSW\n"\
+"hKClhsN3lCSXROQTJ0b2dpdU80V20yVXpvUzhuZ1Y5Z0w3dVE9PQotLS0tLUVORCBFQyBQ\n"\
+"UklWQVRFIEtFWS0tLS0tCgAAAAAAAAAbZGptQGRqbS5zeWQuY29ycC5nb29nbGUuY29tAQ\n"\
+"IDBAUG\n"\
+"-----END OPENSSH PRIVATE KEY-----\n"
+#define PUB_ECDSA_SK \
+"sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBNjJTvrOinVU5vgN8pZidHlvRM4LfPDwPM5sB8dYHmjrGWz605iISV5e8gSLTQNraIIrjuFptlM6EvJ4FfYC+7kAAAAEc3NoOg=="
+#define CERT_ECDSA_SK \
+"sk-ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAK3NrLWVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgKLHtIca++5VoDrUAXU/KqGJZ7jZEnuJSTvt7VrYY9foAAAAIbmlzdHAyNTYAAABBBNjJTvrOinVU5vgN8pZidHlvRM4LfPDwPM5sB8dYHmjrGWz605iISV5e8gSLTQNraIIrjuFptlM6EvJ4FfYC+7kAAAAEc3NoOgAAAAAAAAPqAAAAAQAAAAd1bHlzc2VzAAAAFwAAAAd1bHlzc2VzAAAACG9keXNzZXVzAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMDAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEB1naZOQDLaDr+fwn6E9x8/8HeiaUubDzPexfNQMz+m/7RD0gd5uJhHYUfDb5+/sIx1I7bUEeRIDkBbmZ2foo0E"
+#define PRIV_ED25519_SK \
+"-----BEGIN OPENSSH PRIVATE KEY-----\n"\
+"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAABpzay1zc2\n"\
+"gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAACCTJtH10vWhIDxd62edvMLg9u2cwYKyqa7332je\n"\
+"RArHjAAAAARzc2g6AAAAwN7vvE3e77xNAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY2\n"\
+"9tAAAAIJMm0fXS9aEgPF3rZ528wuD27ZzBgrKprvffaN5ECseMAAAABHNzaDoBAAAAQEsS\n"\
+"xLFiVzfpH2mt9xh8i/zmHV646Hud4QruNBAGNl8gkybR9dL1oSA8XetnnbzC4PbtnMGCsq\n"\
+"mu999o3kQKx4wAAAAAAAAAG2RqbUBkam0uc3lkLmNvcnAuZ29vZ2xlLmNvbQECAwQFBg==\n"\
+"-----END OPENSSH PRIVATE KEY-----\n"
+#define PUB_ED25519_SK \
+"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIJMm0fXS9aEgPF3rZ528wuD27ZzBgrKprvffaN5ECseMAAAABHNzaDo="
+#define CERT_ED25519_SK \
+"sk-ssh-ed25519-cert-v01@openssh.com AAAAI3NrLXNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIJiT+C/VLMWholFZ4xhOyJr0nSLZSFRIM3I07wUNTRPaAAAAIJMm0fXS9aEgPF3rZ528wuD27ZzBgrKprvffaN5ECseMAAAABHNzaDoAAAAAAAAD7AAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAX0Pu13B94pVR3qq8MJQGkOS1Cd7AAM1k6O2VSwyDPM/LfsWIQ4ywgxDmk3hjXWOY7BqljuMxo5VO4JymEIhQBA=="
diff --git a/regress/misc/fuzz-harness/kex_fuzz.cc b/regress/misc/fuzz-harness/kex_fuzz.cc
new file mode 100644
index 000000000000..4740a7cb04c1
--- /dev/null
+++ b/regress/misc/fuzz-harness/kex_fuzz.cc
@@ -0,0 +1,461 @@
+// libfuzzer driver for key exchange fuzzing.
+
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern "C" {
+
+#include "includes.h"
+#include "ssherr.h"
+#include "ssh_api.h"
+#include "sshbuf.h"
+#include "packet.h"
+#include "myproposal.h"
+#include "xmalloc.h"
+#include "authfile.h"
+#include "log.h"
+
+#include "fixed-keys.h"
+
+// Define if you want to generate traces.
+/* #define STANDALONE 1 */
+
+static int prepare_key(struct shared_state *st, int keytype, int bits);
+
+struct shared_state {
+ size_t nkeys;
+ struct sshkey **privkeys, **pubkeys;
+};
+
+struct test_state {
+ struct sshbuf *smsgs, *cmsgs; /* output, for standalone mode */
+ struct sshbuf *sin, *cin; /* input; setup per-test in do_kex_with_key */
+ struct sshbuf *s_template, *c_template; /* main copy of input */
+};
+
+static int
+do_send_and_receive(struct ssh *from, struct ssh *to,
+ struct sshbuf *store, int clobber, size_t *n)
+{
+ u_char type;
+ size_t len;
+ const u_char *buf;
+ int r;
+
+ for (*n = 0;; (*n)++) {
+ if ((r = ssh_packet_next(from, &type)) != 0) {
+ debug_fr(r, "ssh_packet_next");
+ return r;
+ }
+ if (type != 0)
+ return 0;
+ buf = ssh_output_ptr(from, &len);
+ debug_f("%zu%s", len, clobber ? " ignore" : "");
+ if (len == 0)
+ return 0;
+ if ((r = ssh_output_consume(from, len)) != 0) {
+ debug_fr(r, "ssh_output_consume");
+ return r;
+ }
+ if (store != NULL && (r = sshbuf_put(store, buf, len)) != 0) {
+ debug_fr(r, "sshbuf_put");
+ return r;
+ }
+ if (!clobber && (r = ssh_input_append(to, buf, len)) != 0) {
+ debug_fr(r, "ssh_input_append");
+ return r;
+ }
+ }
+}
+
+static int
+run_kex(struct test_state *ts, struct ssh *client, struct ssh *server)
+{
+ int r = 0;
+ size_t cn, sn;
+
+ /* If fuzzing, replace server/client input */
+ if (ts->sin != NULL) {
+ if ((r = ssh_input_append(server, sshbuf_ptr(ts->sin),
+ sshbuf_len(ts->sin))) != 0) {
+ error_fr(r, "ssh_input_append");
+ return r;
+ }
+ sshbuf_reset(ts->sin);
+ }
+ if (ts->cin != NULL) {
+ if ((r = ssh_input_append(client, sshbuf_ptr(ts->cin),
+ sshbuf_len(ts->cin))) != 0) {
+ error_fr(r, "ssh_input_append");
+ return r;
+ }
+ sshbuf_reset(ts->cin);
+ }
+ while (!server->kex->done || !client->kex->done) {
+ cn = sn = 0;
+ debug_f("S:");
+ if ((r = do_send_and_receive(server, client,
+ ts->smsgs, ts->cin != NULL, &sn)) != 0) {
+ debug_fr(r, "S->C");
+ break;
+ }
+ debug_f("C:");
+ if ((r = do_send_and_receive(client, server,
+ ts->cmsgs, ts->sin != NULL, &cn)) != 0) {
+ debug_fr(r, "C->S");
+ break;
+ }
+ if (cn == 0 && sn == 0) {
+ debug_f("kex stalled");
+ r = SSH_ERR_PROTOCOL_ERROR;
+ break;
+ }
+ }
+ debug_fr(r, "done");
+ return r;
+}
+
+static void
+store_key(struct shared_state *st, struct sshkey *pubkey,
+ struct sshkey *privkey)
+{
+ if (st == NULL || pubkey->type < 0 || pubkey->type > INT_MAX ||
+ privkey->type != pubkey->type ||
+ ((size_t)pubkey->type < st->nkeys &&
+ st->pubkeys[pubkey->type] != NULL))
+ abort();
+ if ((size_t)pubkey->type >= st->nkeys) {
+ st->pubkeys = (struct sshkey **)xrecallocarray(st->pubkeys,
+ st->nkeys, pubkey->type + 1, sizeof(*st->pubkeys));
+ st->privkeys = (struct sshkey **)xrecallocarray(st->privkeys,
+ st->nkeys, privkey->type + 1, sizeof(*st->privkeys));
+ st->nkeys = privkey->type + 1;
+ }
+ debug_f("store %s at %d", sshkey_ssh_name(pubkey), pubkey->type);
+ st->pubkeys[pubkey->type] = pubkey;
+ st->privkeys[privkey->type] = privkey;
+}
+
+static int
+prepare_keys(struct shared_state *st)
+{
+ if (prepare_key(st, KEY_RSA, 2048) != 0 ||
+ prepare_key(st, KEY_DSA, 1024) != 0 ||
+ prepare_key(st, KEY_ECDSA, 256) != 0 ||
+ prepare_key(st, KEY_ED25519, 256) != 0) {
+ error_f("key prepare failed");
+ return -1;
+ }
+ return 0;
+}
+
+static struct sshkey *
+get_pubkey(struct shared_state *st, int keytype)
+{
+ if (st == NULL || keytype < 0 || (size_t)keytype >= st->nkeys ||
+ st->pubkeys == NULL || st->pubkeys[keytype] == NULL)
+ abort();
+ return st->pubkeys[keytype];
+}
+
+static struct sshkey *
+get_privkey(struct shared_state *st, int keytype)
+{
+ if (st == NULL || keytype < 0 || (size_t)keytype >= st->nkeys ||
+ st->privkeys == NULL || st->privkeys[keytype] == NULL)
+ abort();
+ return st->privkeys[keytype];
+}
+
+static int
+do_kex_with_key(struct shared_state *st, struct test_state *ts,
+ const char *kex, int keytype)
+{
+ struct ssh *client = NULL, *server = NULL;
+ struct sshkey *privkey = NULL, *pubkey = NULL;
+ struct sshbuf *state = NULL;
+ struct kex_params kex_params;
+ const char *ccp, *proposal[PROPOSAL_MAX] = { KEX_CLIENT };
+ char *myproposal[PROPOSAL_MAX] = {0}, *keyname = NULL;
+ int i, r;
+
+ ts->cin = ts->sin = NULL;
+ if (ts->c_template != NULL &&
+ (ts->cin = sshbuf_fromb(ts->c_template)) == NULL)
+ abort();
+ if (ts->s_template != NULL &&
+ (ts->sin = sshbuf_fromb(ts->s_template)) == NULL)
+ abort();
+
+ pubkey = get_pubkey(st, keytype);
+ privkey = get_privkey(st, keytype);
+ keyname = xstrdup(sshkey_ssh_name(privkey));
+ if (ts->cin != NULL) {
+ debug_f("%s %s clobber client %zu", kex, keyname,
+ sshbuf_len(ts->cin));
+ } else if (ts->sin != NULL) {
+ debug_f("%s %s clobber server %zu", kex, keyname,
+ sshbuf_len(ts->sin));
+ } else
+ debug_f("%s %s noclobber", kex, keyname);
+
+ for (i = 0; i < PROPOSAL_MAX; i++) {
+ ccp = proposal[i];
+#ifdef CIPHER_NONE_AVAIL
+ if (i == PROPOSAL_ENC_ALGS_CTOS || i == PROPOSAL_ENC_ALGS_STOC)
+ ccp = "none";
+#endif
+ if (i == PROPOSAL_SERVER_HOST_KEY_ALGS)
+ ccp = keyname;
+ else if (i == PROPOSAL_KEX_ALGS && kex != NULL)
+ ccp = kex;
+ if ((myproposal[i] = strdup(ccp)) == NULL) {
+ error_f("strdup prop %d", i);
+ goto fail;
+ }
+ }
+ memcpy(kex_params.proposal, myproposal, sizeof(myproposal));
+ if ((r = ssh_init(&client, 0, &kex_params)) != 0) {
+ error_fr(r, "init client");
+ goto fail;
+ }
+ if ((r = ssh_init(&server, 1, &kex_params)) != 0) {
+ error_fr(r, "init server");
+ goto fail;
+ }
+ if ((r = ssh_add_hostkey(server, privkey)) != 0 ||
+ (r = ssh_add_hostkey(client, pubkey)) != 0) {
+ error_fr(r, "add hostkeys");
+ goto fail;
+ }
+ if ((r = run_kex(ts, client, server)) != 0) {
+ error_fr(r, "kex");
+ goto fail;
+ }
+ /* XXX rekex, set_state, etc */
+ fail:
+ for (i = 0; i < PROPOSAL_MAX; i++)
+ free(myproposal[i]);
+ sshbuf_free(ts->sin);
+ sshbuf_free(ts->cin);
+ sshbuf_free(state);
+ ssh_free(client);
+ ssh_free(server);
+ free(keyname);
+ return r;
+}
+
+static int
+prepare_key(struct shared_state *st, int kt, int bits)
+{
+ const char *pubstr = NULL;
+ const char *privstr = NULL;
+ char *tmp, *cp;
+ struct sshkey *privkey = NULL, *pubkey = NULL;
+ struct sshbuf *b = NULL;
+ int r;
+
+ switch (kt) {
+ case KEY_RSA:
+ pubstr = PUB_RSA;
+ privstr = PRIV_RSA;
+ break;
+ case KEY_DSA:
+ pubstr = PUB_DSA;
+ privstr = PRIV_DSA;
+ break;
+ case KEY_ECDSA:
+ pubstr = PUB_ECDSA;
+ privstr = PRIV_ECDSA;
+ break;
+ case KEY_ED25519:
+ pubstr = PUB_ED25519;
+ privstr = PRIV_ED25519;
+ break;
+ default:
+ abort();
+ }
+ if ((b = sshbuf_from(privstr, strlen(privstr))) == NULL)
+ abort();
+ if ((r = sshkey_parse_private_fileblob(b, "", &privkey, NULL)) != 0) {
+ error_fr(r, "priv %d", kt);
+ abort();
+ }
+ sshbuf_free(b);
+ tmp = cp = xstrdup(pubstr);
+ if ((pubkey = sshkey_new(KEY_UNSPEC)) == NULL)
+ abort();
+ if ((r = sshkey_read(pubkey, &cp)) != 0) {
+ error_fr(r, "pub %d", kt);
+ abort();
+ }
+ free(tmp);
+
+ store_key(st, pubkey, privkey);
+ return 0;
+}
+
+#if defined(STANDALONE)
+
+#if 0 /* use this if generating new keys to embed above */
+static int
+prepare_key(struct shared_state *st, int keytype, int bits)
+{
+ struct sshkey *privkey = NULL, *pubkey = NULL;
+ int r;
+
+ if ((r = sshkey_generate(keytype, bits, &privkey)) != 0) {
+ error_fr(r, "generate");
+ abort();
+ }
+ if ((r = sshkey_from_private(privkey, &pubkey)) != 0) {
+ error_fr(r, "make pubkey");
+ abort();
+ }
+ store_key(st, pubkey, privkey);
+ return 0;
+}
+#endif
+
+int main(void)
+{
+ static struct shared_state *st;
+ struct test_state *ts;
+ const int keytypes[] = { KEY_RSA, KEY_DSA, KEY_ECDSA, KEY_ED25519, -1 };
+ const char *kextypes[] = {
+ "sntrup761x25519-sha512@openssh.com",
+ "curve25519-sha256@libssh.org",
+ "ecdh-sha2-nistp256",
+ "diffie-hellman-group1-sha1",
+ "diffie-hellman-group-exchange-sha1",
+ NULL,
+ };
+ int i, j;
+ char *path;
+ FILE *f;
+
+ log_init("kex_fuzz", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 1);
+
+ if (st == NULL) {
+ st = (struct shared_state *)xcalloc(1, sizeof(*st));
+ prepare_keys(st);
+ }
+ /* Run each kex method for each key and save client/server packets */
+ for (i = 0; keytypes[i] != -1; i++) {
+ for (j = 0; kextypes[j] != NULL; j++) {
+ ts = (struct test_state *)xcalloc(1, sizeof(*ts));
+ ts->smsgs = sshbuf_new();
+ ts->cmsgs = sshbuf_new();
+ do_kex_with_key(st, ts, kextypes[j], keytypes[i]);
+ xasprintf(&path, "S2C-%s-%s",
+ kextypes[j], sshkey_type(st->pubkeys[keytypes[i]]));
+ debug_f("%s", path);
+ if ((f = fopen(path, "wb+")) == NULL)
+ abort();
+ if (fwrite(sshbuf_ptr(ts->smsgs), 1,
+ sshbuf_len(ts->smsgs), f) != sshbuf_len(ts->smsgs))
+ abort();
+ fclose(f);
+ free(path);
+ //sshbuf_dump(ts->smsgs, stderr);
+ xasprintf(&path, "C2S-%s-%s",
+ kextypes[j], sshkey_type(st->pubkeys[keytypes[i]]));
+ debug_f("%s", path);
+ if ((f = fopen(path, "wb+")) == NULL)
+ abort();
+ if (fwrite(sshbuf_ptr(ts->cmsgs), 1,
+ sshbuf_len(ts->cmsgs), f) != sshbuf_len(ts->cmsgs))
+ abort();
+ fclose(f);
+ free(path);
+ //sshbuf_dump(ts->cmsgs, stderr);
+ sshbuf_free(ts->smsgs);
+ sshbuf_free(ts->cmsgs);
+ free(ts);
+ }
+ }
+ for (i = 0; keytypes[i] != -1; i++) {
+ xasprintf(&path, "%s.priv",
+ sshkey_type(st->privkeys[keytypes[i]]));
+ debug_f("%s", path);
+ if (sshkey_save_private(st->privkeys[keytypes[i]], path,
+ "", "", SSHKEY_PRIVATE_OPENSSH, NULL, 0) != 0)
+ abort();
+ free(path);
+ xasprintf(&path, "%s.pub",
+ sshkey_type(st->pubkeys[keytypes[i]]));
+ debug_f("%s", path);
+ if (sshkey_save_public(st->pubkeys[keytypes[i]], path, "") != 0)
+ abort();
+ free(path);
+ }
+}
+#else /* !STANDALONE */
+static void
+do_kex(struct shared_state *st, struct test_state *ts, const char *kex)
+{
+ do_kex_with_key(st, ts, kex, KEY_RSA);
+ do_kex_with_key(st, ts, kex, KEY_DSA);
+ do_kex_with_key(st, ts, kex, KEY_ECDSA);
+ do_kex_with_key(st, ts, kex, KEY_ED25519);
+}
+
+static void
+kex_tests(struct shared_state *st, struct test_state *ts)
+{
+ do_kex(st, ts, "sntrup761x25519-sha512@openssh.com");
+ do_kex(st, ts, "curve25519-sha256@libssh.org");
+ do_kex(st, ts, "ecdh-sha2-nistp256");
+ do_kex(st, ts, "diffie-hellman-group1-sha1");
+ do_kex(st, ts, "diffie-hellman-group-exchange-sha1");
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
+{
+ static struct shared_state *st;
+ struct test_state *ts;
+ u_char crbuf[SSH_MAX_PRE_BANNER_LINES * 4];
+ u_char zbuf[4096] = {0};
+ static LogLevel loglevel = SYSLOG_LEVEL_INFO;
+
+ if (st == NULL) {
+ if (getenv("DEBUG") != NULL || getenv("KEX_FUZZ_DEBUG") != NULL)
+ loglevel = SYSLOG_LEVEL_DEBUG3;
+ log_init("kex_fuzz",
+ loglevel, SYSLOG_FACILITY_AUTH, 1);
+ st = (struct shared_state *)xcalloc(1, sizeof(*st));
+ prepare_keys(st);
+ }
+
+ /* Ensure that we can complete (fail) banner exchange at least */
+ memset(crbuf, '\n', sizeof(crbuf));
+
+ ts = (struct test_state *)xcalloc(1, sizeof(*ts));
+ if ((ts->s_template = sshbuf_new()) == NULL ||
+ sshbuf_put(ts->s_template, data, size) != 0 ||
+ sshbuf_put(ts->s_template, crbuf, sizeof(crbuf)) != 0 ||
+ sshbuf_put(ts->s_template, zbuf, sizeof(zbuf)) != 0)
+ abort();
+ kex_tests(st, ts);
+ sshbuf_free(ts->s_template);
+ free(ts);
+
+ ts = (struct test_state *)xcalloc(1, sizeof(*ts));
+ if ((ts->c_template = sshbuf_new()) == NULL ||
+ sshbuf_put(ts->c_template, data, size) != 0 ||
+ sshbuf_put(ts->c_template, crbuf, sizeof(crbuf)) != 0 ||
+ sshbuf_put(ts->c_template, zbuf, sizeof(zbuf)) != 0)
+ abort();
+ kex_tests(st, ts);
+ sshbuf_free(ts->c_template);
+ free(ts);
+
+ return 0;
+}
+#endif /* STANDALONE */
+} /* extern "C" */
diff --git a/regress/misc/fuzz-harness/testdata/README b/regress/misc/fuzz-harness/testdata/README
new file mode 100644
index 000000000000..752053001ac4
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/README
@@ -0,0 +1,4 @@
+This is preparatory data for fuzzing testing including scripts and test keys,
+corresponding to ../fixed-keys that are used in the fuzz tests and consequent
+fuzzing seed corpora. They should not be changed unless the affected seed
+corpora are also regenerated.
diff --git a/regress/misc/fuzz-harness/testdata/create-agent-corpus.sh b/regress/misc/fuzz-harness/testdata/create-agent-corpus.sh
new file mode 100755
index 000000000000..1043b9ff47d7
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/create-agent-corpus.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# Exercise ssh-agent to generate fuzzing corpus
+
+# XXX assumes agent hacked up with sk-dummy.o and ssh-sk.o linked directly
+# and dumping of e->request for each message.
+
+set -xe
+SSH_AUTH_SOCK=$PWD/sock
+rm -f agent-[0-9]* $SSH_AUTH_SOCK
+export SSH_AUTH_SOCK
+../../../../ssh-agent -D -a $SSH_AUTH_SOCK &
+sleep 1
+AGENT_PID=$!
+trap "kill $AGENT_PID" EXIT
+
+PRIV="id_dsa id_ecdsa id_ecdsa_sk id_ed25519 id_ed25519_sk id_rsa"
+
+# add keys
+ssh-add $PRIV
+
+# sign
+ssh-add -T *.pub
+
+# list
+ssh-add -l
+
+# remove individually
+ssh-add -d $PRIV
+
+# re-add with constraints
+ssh-add -c -t 3h $PRIV
+
+# delete all
+ssh-add -D
+
+# attempt to add a PKCS#11 token
+ssh-add -s /fake || :
+
+# attempt to delete PKCS#11
+ssh-add -e /fake || :
+
+ssh-add -L
+
diff --git a/regress/misc/fuzz-harness/testdata/id_dsa b/regress/misc/fuzz-harness/testdata/id_dsa
new file mode 100644
index 000000000000..88bf5566c93b
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_dsa
@@ -0,0 +1,21 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsgAAAAdzc2gtZH
+NzAAAAgQCsGTfjpQ465EOkfQXJM9BOvfRQE0fqlykAls+ncz+T7hrbeScRu8xpwzsznJNm
+xlW8o6cUDiHmBJ5OHgamUC9N7YJeU/6fnOAZifgN8mqK6k8pKHuje8ANOiYgHLl0yiASQA
+3//qMyzZ+W/hemoLSmLAbEqlfWVeyYx+wta1Vm+QAAABUAvWyehvUvdHvQxavYgS5p0t5Q
+d7UAAACBAIRA9Yy+f4Kzqpv/qICPO3zk42UuP7WAhSW2nCbQdLlCiSTxcjKgcvXNRckwJP
+44JjSHOtJy/AMtJrPIbLYG6KuWTdBlEHFiG6DafvLG+qPMSL2bPjXTOhuOMbCHIZ+5WBkW
+THeG/Nv11iI01Of9V6tXkig23K370flkRkXFi9MdAAAAgCt6YUcQkNwG7B/e5M1FZsLP9O
+kVB3BwLAOjmWdHpyhu3HpwSJa3XLEvhXN0i6IVI2KgPo/2GtYA6rHt14L+6u1pmhh8sAvQ
+ksp3qZB+xh/NP+hBqf0sbHX0yYbzKOvI5SCc/kKK6yagcBZOsubM/KC8TxyVgmD5c6WzYs
+h5TEpvAAAB2PHjRbbx40W2AAAAB3NzaC1kc3MAAACBAKwZN+OlDjrkQ6R9Bckz0E699FAT
+R+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4B
+mJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1r
+VWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS
+4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIb
+oNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRc
+WL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SL
+ohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJ
+z+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8AAAAUUA+OGldMi76ClO/sstpdbBUE
+lq8AAAAAAQI=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/misc/fuzz-harness/testdata/id_dsa-cert.pub b/regress/misc/fuzz-harness/testdata/id_dsa-cert.pub
new file mode 100644
index 000000000000..3afb87fe62f7
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_dsa-cert.pub
@@ -0,0 +1 @@
+ssh-dss-cert-v01@openssh.com AAAAHHNzaC1kc3MtY2VydC12MDFAb3BlbnNzaC5jb20AAAAguF716Yub+vVKNlONKLsfxGYWkRe/PyjfYdGRTsFaDvAAAACBAKwZN+OlDjrkQ6R9Bckz0E699FATR+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4BmJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1rVWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIboNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRcWL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SLohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJz+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8AAAAAAAAD6AAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAjMQEZcbdUYJBjIC4GxByFDOb8tv71vDZdx7irHwaqIjx5rzpJUuOV1r8ZO4kY+Yaiun1yrWj2QYkfJrHBvD1DA== id_dsa.pub
diff --git a/regress/misc/fuzz-harness/testdata/id_dsa.pub b/regress/misc/fuzz-harness/testdata/id_dsa.pub
new file mode 100644
index 000000000000..6f91c4e07336
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_dsa.pub
@@ -0,0 +1 @@
+ssh-dss AAAAB3NzaC1kc3MAAACBAKwZN+OlDjrkQ6R9Bckz0E699FATR+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4BmJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1rVWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIboNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRcWL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SLohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJz+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8=
diff --git a/regress/misc/fuzz-harness/testdata/id_ecdsa b/regress/misc/fuzz-harness/testdata/id_ecdsa
new file mode 100644
index 000000000000..c1a96c6f9eaf
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ecdsa
@@ -0,0 +1,8 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
+1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTDJ0VlMv+0rguNzaJ1DF2KueHaxRSQ
+6LpIxGbulrg1a8RPbnMXwag5GcDiDllD2lDUJUuBEWyjXA0rZoZX35ELAAAAoE/Bbr5PwW
+6+AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43N
+onUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQ
+sAAAAhAIhE6hCID5oOm1TDktc++KFKyScjLifcZ6Cgv5xSSyLOAAAAAAECAwQFBgc=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/misc/fuzz-harness/testdata/id_ecdsa-cert.pub b/regress/misc/fuzz-harness/testdata/id_ecdsa-cert.pub
new file mode 100644
index 000000000000..9de599917de6
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ecdsa-cert.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgVJZuM/1AOe6n++qRWMyUuAThYqLvvQxj5CGflLODp60AAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43NonUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQsAAAAAAAAD6QAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAtdJpcF6ZmQL+ueices4QZeL7AK8Xuo08jyLgiolhjKy2jj4LSUki4aX/ZeZeJuby1ovGrfaeFAgx3itPLR7IAQ== id_ecdsa.pub
diff --git a/regress/misc/fuzz-harness/testdata/id_ecdsa.pub b/regress/misc/fuzz-harness/testdata/id_ecdsa.pub
new file mode 100644
index 000000000000..30a7cc23b228
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ecdsa.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43NonUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQs=
diff --git a/regress/misc/fuzz-harness/testdata/id_ecdsa_sk b/regress/misc/fuzz-harness/testdata/id_ecdsa_sk
new file mode 100644
index 000000000000..5a364ed39f1e
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ecdsa_sk
@@ -0,0 +1,14 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAfwAAACJzay1lY2
+RzYS1zaGEyLW5pc3RwMjU2QG9wZW5zc2guY29tAAAACG5pc3RwMjU2AAAAQQTYyU76zop1
+VOb4DfKWYnR5b0TOC3zw8DzObAfHWB5o6xls+tOYiEleXvIEi00Da2iCK47habZTOhLyeB
+X2Avu5AAAABHNzaDoAAAGYqUAQSKlAEEgAAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBv
+cGVuc3NoLmNvbQAAAAhuaXN0cDI1NgAAAEEE2MlO+s6KdVTm+A3ylmJ0eW9Ezgt88PA8zm
+wHx1geaOsZbPrTmIhJXl7yBItNA2togiuO4Wm2UzoS8ngV9gL7uQAAAARzc2g6AQAAAOMt
+LS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUhjQ0FRRUVJSHFsZjNsWTkxZFhwUn
+dYZDBrS0lYWmNpeDRRcDBNSU15Ny9JMUxXSTFuWG9Bb0dDQ3FHU000OQpBd0VIb1VRRFFn
+QUUyTWxPK3M2S2RWVG0rQTN5bG1KMGVXOUV6Z3Q4OFBBOHptd0h4MWdlYU9zWmJQclRtSW
+hKClhsN3lCSXROQTJ0b2dpdU80V20yVXpvUzhuZ1Y5Z0w3dVE9PQotLS0tLUVORCBFQyBQ
+UklWQVRFIEtFWS0tLS0tCgAAAAAAAAAbZGptQGRqbS5zeWQuY29ycC5nb29nbGUuY29tAQ
+IDBAUG
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/misc/fuzz-harness/testdata/id_ecdsa_sk-cert.pub b/regress/misc/fuzz-harness/testdata/id_ecdsa_sk-cert.pub
new file mode 100644
index 000000000000..14040fad7aa6
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ecdsa_sk-cert.pub
@@ -0,0 +1 @@
+sk-ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAK3NrLWVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgKLHtIca++5VoDrUAXU/KqGJZ7jZEnuJSTvt7VrYY9foAAAAIbmlzdHAyNTYAAABBBNjJTvrOinVU5vgN8pZidHlvRM4LfPDwPM5sB8dYHmjrGWz605iISV5e8gSLTQNraIIrjuFptlM6EvJ4FfYC+7kAAAAEc3NoOgAAAAAAAAPqAAAAAQAAAAd1bHlzc2VzAAAAFwAAAAd1bHlzc2VzAAAACG9keXNzZXVzAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMDAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEB1naZOQDLaDr+fwn6E9x8/8HeiaUubDzPexfNQMz+m/7RD0gd5uJhHYUfDb5+/sIx1I7bUEeRIDkBbmZ2foo0E djm@djm.syd.corp.google.com
diff --git a/regress/misc/fuzz-harness/testdata/id_ecdsa_sk.pub b/regress/misc/fuzz-harness/testdata/id_ecdsa_sk.pub
new file mode 100644
index 000000000000..1b5e829b7418
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ecdsa_sk.pub
@@ -0,0 +1 @@
+sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBNjJTvrOinVU5vgN8pZidHlvRM4LfPDwPM5sB8dYHmjrGWz605iISV5e8gSLTQNraIIrjuFptlM6EvJ4FfYC+7kAAAAEc3NoOg== djm@djm.syd.corp.google.com
diff --git a/regress/misc/fuzz-harness/testdata/id_ed25519 b/regress/misc/fuzz-harness/testdata/id_ed25519
new file mode 100644
index 000000000000..6a7fbac929d1
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ed25519
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+QyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAIhWlP99VpT/
+fQAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAw
+AAAEDE1rlcMC0s0X3TKVZAOVavZOywwkXw8tO5dLObxaCMEDPQXmEVMVLmeFRyafKMVWgP
+Dkv8/uRBTwmcEDatZzMDAAAAAAECAwQF
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/misc/fuzz-harness/testdata/id_ed25519-cert.pub b/regress/misc/fuzz-harness/testdata/id_ed25519-cert.pub
new file mode 100644
index 000000000000..6a95fed2ac80
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ed25519-cert.pub
@@ -0,0 +1 @@
+ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIMDQjYH6XRzH3j3MW1DdjCoAfvrHfgjnVGF+sLK0pBfqAAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMDAAAAAAAAA+sAAAABAAAAB3VseXNzZXMAAAAXAAAAB3VseXNzZXMAAAAIb2R5c3NldXMAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgM9BeYRUxUuZ4VHJp8oxVaA8OS/z+5EFPCZwQNq1nMwMAAABTAAAAC3NzaC1lZDI1NTE5AAAAQBj0og+s09/HpwdHZbzN0twooKPDWWrxGfnP1Joy6cDnY2BCSQ7zg9vbq11kLF8H/sKOTZWAQrUZ7LlChOu9Ogw= id_ed25519.pub
diff --git a/regress/misc/fuzz-harness/testdata/id_ed25519.pub b/regress/misc/fuzz-harness/testdata/id_ed25519.pub
new file mode 100644
index 000000000000..87b61744701f
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ed25519.pub
@@ -0,0 +1,2 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMD
+
diff --git a/regress/misc/fuzz-harness/testdata/id_ed25519_sk b/regress/misc/fuzz-harness/testdata/id_ed25519_sk
new file mode 100644
index 000000000000..9dcda6c4626f
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ed25519_sk
@@ -0,0 +1,8 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAABpzay1zc2
+gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAACCTJtH10vWhIDxd62edvMLg9u2cwYKyqa7332je
+RArHjAAAAARzc2g6AAAAwN7vvE3e77xNAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY2
+9tAAAAIJMm0fXS9aEgPF3rZ528wuD27ZzBgrKprvffaN5ECseMAAAABHNzaDoBAAAAQEsS
+xLFiVzfpH2mt9xh8i/zmHV646Hud4QruNBAGNl8gkybR9dL1oSA8XetnnbzC4PbtnMGCsq
+mu999o3kQKx4wAAAAAAAAAG2RqbUBkam0uc3lkLmNvcnAuZ29vZ2xlLmNvbQECAwQFBg==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/misc/fuzz-harness/testdata/id_ed25519_sk-cert.pub b/regress/misc/fuzz-harness/testdata/id_ed25519_sk-cert.pub
new file mode 100644
index 000000000000..9e41eec00df4
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ed25519_sk-cert.pub
@@ -0,0 +1 @@
+sk-ssh-ed25519-cert-v01@openssh.com AAAAI3NrLXNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIJiT+C/VLMWholFZ4xhOyJr0nSLZSFRIM3I07wUNTRPaAAAAIJMm0fXS9aEgPF3rZ528wuD27ZzBgrKprvffaN5ECseMAAAABHNzaDoAAAAAAAAD7AAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAX0Pu13B94pVR3qq8MJQGkOS1Cd7AAM1k6O2VSwyDPM/LfsWIQ4ywgxDmk3hjXWOY7BqljuMxo5VO4JymEIhQBA== djm@djm.syd.corp.google.com
diff --git a/regress/misc/fuzz-harness/testdata/id_ed25519_sk.pub b/regress/misc/fuzz-harness/testdata/id_ed25519_sk.pub
new file mode 100644
index 000000000000..38d198444b79
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ed25519_sk.pub
@@ -0,0 +1 @@
+sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIJMm0fXS9aEgPF3rZ528wuD27ZzBgrKprvffaN5ECseMAAAABHNzaDo= djm@djm.syd.corp.google.com
diff --git a/regress/misc/fuzz-harness/testdata/id_rsa b/regress/misc/fuzz-harness/testdata/id_rsa
new file mode 100644
index 000000000000..574fecf47008
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_rsa
@@ -0,0 +1,27 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAQEA3+epf+VGKoGPaAZXrf6S0cyumQnddkGBnVFX0A5eh37RtLug0qY5
+thxsBUbGGVr9mTd2QXwLujBwYg5l1MP/Fmg+5312Zgx9pHmS+qKULbar0hlNgptNEb+aNU
+d3o9qg3aXqXm7+ZnjAV05ef/mxNRN2ZvuEkw7cRppTJcbBI+vF3lXuCXnX2klDI95Gl2AW
+3WHRtanqLHZXuBkjjRBDKc7MUq/GP1hmLiAd95dvU7fZjRlIEsP84zGEI1Fb0L/kmPHcOt
+iVfHft8CtmC9v6+94JrOiPBBNScV+dyrgAGPsdKdr/1vIpQmCNiI8s3PCiD8J7ZiBaYm0I
+8fq5G/qnUwAAA7ggw2dXIMNnVwAAAAdzc2gtcnNhAAABAQDf56l/5UYqgY9oBlet/pLRzK
+6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZm
+DH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGml
+MlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29T
+t9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v
+/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdTAAAAAwEAAQAAAQEArWm5B4tFasppjUHM
+SsAuajtCxtizI1Hc10EW59cZM4vvUzE2f6+qZvdgWj3UU/L7Et23w0QVuSCnCerox379ZB
+ddEOFFAAiQjwBx65hbd4RRUymxtIQfjq18++LcMJW1nbVQ7c69ThQbtALIggmbS+ZE/8Gx
+jkwmIrCH0Ww8TlpsPe+mNHuyNk7UEZoXLm22lNLqq5qkIL5JgT6M2iNJpMOJy9/CKi6kO4
+JPuVwjdG4C5pBPaMN3KJ1IvAlSlLGNaXnfXcn85gWfsCjsZmH3liey2NJamqp/w83BrKUg
+YZvMR2qeWZaKkFTahpzN5KRK1BFeB37O0P84Dzh1biDX8QAAAIEAiWXW8ePYFwLpa2mFIh
+VvRTdcrN70rVK5eWVaL3pyS4vGA56Jixq86dHveOnbSY+iNb1jQidtXc8SWUt2wtHqZ32h
+Lji9/hMSKqe9SEP3xvDRDmUJqsVw0ySyrFrzm4160QY6RKU3CIQCVFslMZ9fxmrfZ/hxoU
+0X3FVsxmC4+kwAAACBAPOc1YERpV6PjANBrGR+1o1RCdACbm5myc42QzSNIaOZmgrYs+Gt
+7+EcoqSdbJzHJNCNQfF+A+vjbIkFiuZqq/5wwr59qXx5OAlijLB/ywwKmTWq6lp//Zxny+
+ka3sIGNO14eQvmxNDnlLL+RIZleCTEKBXSW6CZhr+uHMZFKKMtAAAAgQDrSkm+LbILB7H9
+jxEBZLhv53aAn4u81kFKQOJ7PzzpBGSoD12i7oIJu5siSD5EKDNVEr+SvCf0ISU3BuMpzl
+t3YrPrHRheOFhn5e3j0e//zB8rBC0DGB4CtTDdeh7rOXUL4K0pz+8wEpNkV62SWxhC6NRW
+I79JhtGkh+GtcnkEfwAAAAAB
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/misc/fuzz-harness/testdata/id_rsa-cert.pub b/regress/misc/fuzz-harness/testdata/id_rsa-cert.pub
new file mode 100644
index 000000000000..01761a38fa0f
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_rsa-cert.pub
@@ -0,0 +1 @@
+ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAg89JX6OBMYDSxER8fnU5y8xxeMCHR/hI0uVqdEhNyCpcAAAADAQABAAABAQDf56l/5UYqgY9oBlet/pLRzK6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZmDH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGmlMlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29Tt9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdTAAAAAAAAA+0AAAABAAAAB3VseXNzZXMAAAAXAAAAB3VseXNzZXMAAAAIb2R5c3NldXMAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgM9BeYRUxUuZ4VHJp8oxVaA8OS/z+5EFPCZwQNq1nMwMAAABTAAAAC3NzaC1lZDI1NTE5AAAAQGCDA6PWw4x9bHQl0w7NqifHepumqD3dmyMx+hZGuPRon+TsyCjfytu7hWmV7l9XUF0fPQNFQ7FGat5e+7YUNgE= id_rsa.pub
diff --git a/regress/misc/fuzz-harness/testdata/id_rsa.pub b/regress/misc/fuzz-harness/testdata/id_rsa.pub
new file mode 100644
index 000000000000..05015e12bfaa
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDf56l/5UYqgY9oBlet/pLRzK6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZmDH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGmlMlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29Tt9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdT
diff --git a/regress/misc/kexfuzz/Makefile b/regress/misc/kexfuzz/Makefile
deleted file mode 100644
index ede5e2fb4bcf..000000000000
--- a/regress/misc/kexfuzz/Makefile
+++ /dev/null
@@ -1,101 +0,0 @@
-# $OpenBSD: Makefile,v 1.8 2020/04/03 04:07:48 djm Exp $
-
-.include <bsd.own.mk>
-.include <bsd.obj.mk>
-
-# XXX detect from ssh binary?
-SSH1?= no
-OPENSSL?= yes
-
-PROG= kexfuzz
-SRCS= kexfuzz.c
-
-SSHREL=../../../../../usr.bin/ssh
-.PATH: ${.CURDIR}/${SSHREL}
-# From usr.bin/ssh
-SRCS+=sshbuf-getput-basic.c sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c
-SRCS+=atomicio.c sshkey.c authfile.c cipher.c log.c ssh-rsa.c ssh-dss.c
-SRCS+=ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c
-SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c
-SRCS+=addrmatch.c bitmap.c packet.c dispatch.c canohost.c ssh_api.c
-SRCS+=compat.c ed25519.c hash.c ge25519.c fe25519.c sc25519.c verify.c
-SRCS+=cipher-chachapoly.c chacha.c poly1305.c utf8.c
-SRCS+=sshbuf-io.c ssh-ecdsa-sk.c ssh-ed25519-sk.c msg.c ssh-sk-client.c
-
-SRCS+= kex.c
-SRCS+= dh.c
-SRCS+= kexdh.c
-SRCS+= kexecdh.c
-SRCS+= kexgex.c
-SRCS+= kexgexc.c
-SRCS+= kexgexs.c
-SRCS+= kexc25519.c
-SRCS+= smult_curve25519_ref.c
-SRCS+= kexgen.c
-SRCS+= kexsntrup4591761x25519.c
-SRCS+= sntrup4591761.c
-
-SRCS+=digest-openssl.c
-#SRCS+=digest-libc.c
-
-NOMAN= 1
-
-.if (${OPENSSL:L} == "yes")
-CFLAGS+= -DWITH_OPENSSL
-.else
-# SSH v.1 requires OpenSSL.
-SSH1= no
-.endif
-
-.if (${SSH1:L} == "yes")
-CFLAGS+= -DWITH_SSH1
-.endif
-
-LDADD+= -lfido2 -lcbor -lusbhid
-DPADD+= ${LIBFIDO2} ${LIBCBOR} ${LIBUSBHID}
-
-# enable warnings
-WARNINGS=Yes
-
-DEBUG=-g
-CFLAGS+= -fstack-protector-all
-CDIAGFLAGS= -Wall
-CDIAGFLAGS+= -Wextra
-CDIAGFLAGS+= -Werror
-CDIAGFLAGS+= -Wchar-subscripts
-CDIAGFLAGS+= -Wcomment
-CDIAGFLAGS+= -Wformat
-CDIAGFLAGS+= -Wformat-security
-CDIAGFLAGS+= -Wimplicit
-CDIAGFLAGS+= -Winline
-CDIAGFLAGS+= -Wmissing-declarations
-CDIAGFLAGS+= -Wmissing-prototypes
-CDIAGFLAGS+= -Wparentheses
-CDIAGFLAGS+= -Wpointer-arith
-CDIAGFLAGS+= -Wreturn-type
-CDIAGFLAGS+= -Wshadow
-CDIAGFLAGS+= -Wsign-compare
-CDIAGFLAGS+= -Wstrict-aliasing
-CDIAGFLAGS+= -Wstrict-prototypes
-CDIAGFLAGS+= -Wswitch
-CDIAGFLAGS+= -Wtrigraphs
-CDIAGFLAGS+= -Wuninitialized
-CDIAGFLAGS+= -Wunused
-CDIAGFLAGS+= -Wno-unused-parameter
-.if ${COMPILER_VERSION:L} != "gcc3"
-CDIAGFLAGS+= -Wold-style-definition
-.endif
-
-
-CFLAGS+=-I${.CURDIR}/${SSHREL}
-
-LDADD+= -lutil -lz
-DPADD+= ${LIBUTIL} ${LIBZ}
-
-.if (${OPENSSL:L} == "yes")
-LDADD+= -lcrypto
-DPADD+= ${LIBCRYPTO}
-.endif
-
-.include <bsd.prog.mk>
-
diff --git a/regress/misc/kexfuzz/README b/regress/misc/kexfuzz/README
deleted file mode 100644
index 504c26f3bed3..000000000000
--- a/regress/misc/kexfuzz/README
+++ /dev/null
@@ -1,34 +0,0 @@
-This is a harness to help with fuzzing KEX.
-
-To use it, you first set it to count packets in each direction:
-
-./kexfuzz -K diffie-hellman-group1-sha1 -k host_ed25519_key -c
-S2C: 29
-C2S: 31
-
-Then get it to record a particular packet (in this case the 4th
-packet from client->server):
-
-./kexfuzz -K diffie-hellman-group1-sha1 -k host_ed25519_key \
- -d -D C2S -i 3 -f packet_3
-
-Fuzz the packet somehow:
-
-dd if=/dev/urandom of=packet_3 bs=32 count=1 # Just for example
-
-Then re-run the key exchange substituting the modified packet in
-its original sequence:
-
-./kexfuzz -K diffie-hellman-group1-sha1 -k host_ed25519_key \
- -r -D C2S -i 3 -f packet_3
-
-A comprehensive KEX fuzz run would fuzz every packet in both
-directions for each key exchange type and every hostkey type.
-This will take some time.
-
-Limitations: kexfuzz can't change the ordering of packets at
-present. It is limited to replacing individual packets with
-fuzzed variants with the same type. It really should allow
-insertion, deletion on replacement of packets too.
-
-$OpenBSD: README,v 1.3 2017/10/20 02:13:41 djm Exp $
diff --git a/regress/misc/kexfuzz/kexfuzz.c b/regress/misc/kexfuzz/kexfuzz.c
deleted file mode 100644
index 56697c9189e5..000000000000
--- a/regress/misc/kexfuzz/kexfuzz.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/* $OpenBSD: kexfuzz.c,v 1.6 2020/01/26 00:09:50 djm Exp $ */
-/*
- * Fuzz harness for KEX code
- *
- * Placed in the public domain
- */
-
-#include "includes.h"
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <stdio.h>
-#ifdef HAVE_STDINT_H
-# include <stdint.h>
-#endif
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#ifdef HAVE_ERR_H
-# include <err.h>
-#endif
-
-#include "ssherr.h"
-#include "ssh_api.h"
-#include "sshbuf.h"
-#include "packet.h"
-#include "myproposal.h"
-#include "authfile.h"
-#include "log.h"
-
-void kex_tests(void);
-static int do_debug = 0;
-
-enum direction { S2C, C2S };
-
-struct hook_ctx {
- struct ssh *client, *server, *server2;
- int *c2s, *s2c;
- int trigger_direction, packet_index;
- const char *dump_path;
- struct sshbuf *replace_data;
-};
-
-static int
-packet_hook(struct ssh *ssh, struct sshbuf *packet, u_char *typep, void *_ctx)
-{
- struct hook_ctx *ctx = (struct hook_ctx *)_ctx;
- int mydirection = ssh == ctx->client ? S2C : C2S;
- int *packet_count = mydirection == S2C ? ctx->s2c : ctx->c2s;
- FILE *dumpfile;
- int r;
-
- if (do_debug) {
- printf("%s packet %d type %u:\n",
- mydirection == S2C ? "s2c" : "c2s",
- *packet_count, *typep);
- sshbuf_dump(packet, stdout);
- }
- if (mydirection == ctx->trigger_direction &&
- ctx->packet_index == *packet_count) {
- if (ctx->replace_data != NULL) {
- sshbuf_reset(packet);
- /* Type is first byte of packet */
- if ((r = sshbuf_get_u8(ctx->replace_data,
- typep)) != 0 ||
- (r = sshbuf_putb(packet, ctx->replace_data)) != 0)
- return r;
- if (do_debug) {
- printf("***** replaced packet type %u\n",
- *typep);
- sshbuf_dump(packet, stdout);
- }
- } else if (ctx->dump_path != NULL) {
- if ((dumpfile = fopen(ctx->dump_path, "w+")) == NULL)
- err(1, "fopen %s", ctx->dump_path);
- /* Write { type, packet } */
- if (fwrite(typep, 1, 1, dumpfile) != 1)
- err(1, "fwrite type %s", ctx->dump_path);
- if (sshbuf_len(packet) != 0 &&
- fwrite(sshbuf_ptr(packet), sshbuf_len(packet),
- 1, dumpfile) != 1)
- err(1, "fwrite body %s", ctx->dump_path);
- if (do_debug) {
- printf("***** dumped packet type %u len %zu\n",
- *typep, sshbuf_len(packet));
- }
- fclose(dumpfile);
- /* No point in continuing */
- exit(0);
- }
- }
- (*packet_count)++;
- return 0;
-}
-
-static int
-do_send_and_receive(struct ssh *from, struct ssh *to)
-{
- u_char type;
- size_t len;
- const u_char *buf;
- int r;
-
- for (;;) {
- if ((r = ssh_packet_next(from, &type)) != 0) {
- fprintf(stderr, "ssh_packet_next: %s\n", ssh_err(r));
- return r;
- }
-
- if (type != 0)
- return 0;
- buf = ssh_output_ptr(from, &len);
- if (len == 0)
- return 0;
- if ((r = ssh_input_append(to, buf, len)) != 0) {
- debug("ssh_input_append: %s", ssh_err(r));
- return r;
- }
- if ((r = ssh_output_consume(from, len)) != 0) {
- debug("ssh_output_consume: %s", ssh_err(r));
- return r;
- }
- }
-}
-
-/* Minimal test_helper.c scaffholding to make this standalone */
-const char *in_test = NULL;
-#define TEST_START(a) \
- do { \
- in_test = (a); \
- if (do_debug) \
- fprintf(stderr, "test %s starting\n", in_test); \
- } while (0)
-#define TEST_DONE() \
- do { \
- if (do_debug) \
- fprintf(stderr, "test %s done\n", \
- in_test ? in_test : "???"); \
- in_test = NULL; \
- } while(0)
-#define ASSERT_INT_EQ(a, b) \
- do { \
- if ((int)(a) != (int)(b)) { \
- fprintf(stderr, "%s %s:%d " \
- "%s (%d) != expected %s (%d)\n", \
- in_test ? in_test : "(none)", \
- __func__, __LINE__, #a, (int)(a), #b, (int)(b)); \
- exit(2); \
- } \
- } while (0)
-#define ASSERT_INT_GE(a, b) \
- do { \
- if ((int)(a) < (int)(b)) { \
- fprintf(stderr, "%s %s:%d " \
- "%s (%d) < expected %s (%d)\n", \
- in_test ? in_test : "(none)", \
- __func__, __LINE__, #a, (int)(a), #b, (int)(b)); \
- exit(2); \
- } \
- } while (0)
-#define ASSERT_PTR_NE(a, b) \
- do { \
- if ((a) == (b)) { \
- fprintf(stderr, "%s %s:%d " \
- "%s (%p) != expected %s (%p)\n", \
- in_test ? in_test : "(none)", \
- __func__, __LINE__, #a, (a), #b, (b)); \
- exit(2); \
- } \
- } while (0)
-
-
-static void
-run_kex(struct ssh *client, struct ssh *server)
-{
- int r = 0;
-
- while (!server->kex->done || !client->kex->done) {
- if ((r = do_send_and_receive(server, client)) != 0) {
- debug("do_send_and_receive S2C: %s", ssh_err(r));
- break;
- }
- if ((r = do_send_and_receive(client, server)) != 0) {
- debug("do_send_and_receive C2S: %s", ssh_err(r));
- break;
- }
- }
- if (do_debug)
- printf("done: %s\n", ssh_err(r));
- ASSERT_INT_EQ(r, 0);
- ASSERT_INT_EQ(server->kex->done, 1);
- ASSERT_INT_EQ(client->kex->done, 1);
-}
-
-static void
-do_kex_with_key(const char *kex, struct sshkey *prvkey, int *c2s, int *s2c,
- int direction, int packet_index,
- const char *dump_path, struct sshbuf *replace_data)
-{
- struct ssh *client = NULL, *server = NULL, *server2 = NULL;
- struct sshkey *pubkey = NULL;
- struct sshbuf *state;
- struct kex_params kex_params;
- char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
- char *keyname = NULL;
- struct hook_ctx hook_ctx;
-
- TEST_START("sshkey_from_private");
- ASSERT_INT_EQ(sshkey_from_private(prvkey, &pubkey), 0);
- TEST_DONE();
-
- TEST_START("ssh_init");
- memcpy(kex_params.proposal, myproposal, sizeof(myproposal));
- if (kex != NULL)
- kex_params.proposal[PROPOSAL_KEX_ALGS] = strdup(kex);
- keyname = strdup(sshkey_ssh_name(prvkey));
- ASSERT_PTR_NE(keyname, NULL);
- kex_params.proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = keyname;
- ASSERT_INT_EQ(ssh_init(&client, 0, &kex_params), 0);
- ASSERT_INT_EQ(ssh_init(&server, 1, &kex_params), 0);
- ASSERT_INT_EQ(ssh_init(&server2, 1, NULL), 0);
- ASSERT_PTR_NE(client, NULL);
- ASSERT_PTR_NE(server, NULL);
- ASSERT_PTR_NE(server2, NULL);
- TEST_DONE();
-
- hook_ctx.c2s = c2s;
- hook_ctx.s2c = s2c;
- hook_ctx.trigger_direction = direction;
- hook_ctx.packet_index = packet_index;
- hook_ctx.dump_path = dump_path;
- hook_ctx.replace_data = replace_data;
- hook_ctx.client = client;
- hook_ctx.server = server;
- hook_ctx.server2 = server2;
- ssh_packet_set_input_hook(client, packet_hook, &hook_ctx);
- ssh_packet_set_input_hook(server, packet_hook, &hook_ctx);
- ssh_packet_set_input_hook(server2, packet_hook, &hook_ctx);
-
- TEST_START("ssh_add_hostkey");
- ASSERT_INT_EQ(ssh_add_hostkey(server, prvkey), 0);
- ASSERT_INT_EQ(ssh_add_hostkey(client, pubkey), 0);
- TEST_DONE();
-
- TEST_START("kex");
- run_kex(client, server);
- TEST_DONE();
-
- TEST_START("rekeying client");
- ASSERT_INT_EQ(kex_send_kexinit(client), 0);
- run_kex(client, server);
- TEST_DONE();
-
- TEST_START("rekeying server");
- ASSERT_INT_EQ(kex_send_kexinit(server), 0);
- run_kex(client, server);
- TEST_DONE();
-
- TEST_START("ssh_packet_get_state");
- state = sshbuf_new();
- ASSERT_PTR_NE(state, NULL);
- ASSERT_INT_EQ(ssh_packet_get_state(server, state), 0);
- ASSERT_INT_GE(sshbuf_len(state), 1);
- TEST_DONE();
-
- TEST_START("ssh_packet_set_state");
- ASSERT_INT_EQ(ssh_add_hostkey(server2, prvkey), 0);
- kex_free(server2->kex); /* XXX or should ssh_packet_set_state()? */
- ASSERT_INT_EQ(ssh_packet_set_state(server2, state), 0);
- ASSERT_INT_EQ(sshbuf_len(state), 0);
- sshbuf_free(state);
- ASSERT_PTR_NE(server2->kex, NULL);
- /* XXX we need to set the callbacks */
-#ifdef WITH_OPENSSL
- server2->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server;
- server2->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server;
- server2->kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_server;
- server2->kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_server;
- server2->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_server;
- server2->kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
- server2->kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
-# ifdef OPENSSL_HAS_ECC
- server2->kex->kex[KEX_ECDH_SHA2] = kex_gen_server;
-# endif
-#endif
- server2->kex->kex[KEX_C25519_SHA256] = kex_gen_server;
- server2->kex->load_host_public_key = server->kex->load_host_public_key;
- server2->kex->load_host_private_key = server->kex->load_host_private_key;
- server2->kex->sign = server->kex->sign;
- TEST_DONE();
-
- TEST_START("rekeying server2");
- ASSERT_INT_EQ(kex_send_kexinit(server2), 0);
- run_kex(client, server2);
- ASSERT_INT_EQ(kex_send_kexinit(client), 0);
- run_kex(client, server2);
- TEST_DONE();
-
- TEST_START("cleanup");
- sshkey_free(pubkey);
- ssh_free(client);
- ssh_free(server);
- ssh_free(server2);
- free(keyname);
- TEST_DONE();
-}
-
-static void
-usage(void)
-{
- fprintf(stderr,
- "Usage: kexfuzz [-hcdrv] [-D direction] [-f data_file]\n"
- " [-K kex_alg] [-k private_key] [-i packet_index]\n"
- "\n"
- "Options:\n"
- " -h Display this help\n"
- " -c Count packets sent during KEX\n"
- " -d Dump mode: record KEX packet to data file\n"
- " -r Replace mode: replace packet with data file\n"
- " -v Turn on verbose logging\n"
- " -D S2C|C2S Packet direction for replacement or dump\n"
- " -f data_file Path to data file for replacement or dump\n"
- " -K kex_alg Name of KEX algorithm to test (see below)\n"
- " -k private_key Path to private key file\n"
- " -i packet_index Index of packet to replace or dump (from 0)\n"
- "\n"
- "Available KEX algorithms: %s\n", kex_alg_list(' '));
-}
-
-static void
-badusage(const char *bad)
-{
- fprintf(stderr, "Invalid options\n");
- fprintf(stderr, "%s\n", bad);
- usage();
- exit(1);
-}
-
-int
-main(int argc, char **argv)
-{
- int ch, fd, r;
- int count_flag = 0, dump_flag = 0, replace_flag = 0;
- int packet_index = -1, direction = -1;
- int s2c = 0, c2s = 0; /* packet counts */
- const char *kex = NULL, *kpath = NULL, *data_path = NULL;
- struct sshkey *key = NULL;
- struct sshbuf *replace_data = NULL;
-
- setvbuf(stdout, NULL, _IONBF, 0);
- while ((ch = getopt(argc, argv, "hcdrvD:f:K:k:i:")) != -1) {
- switch (ch) {
- case 'h':
- usage();
- return 0;
- case 'c':
- count_flag = 1;
- break;
- case 'd':
- dump_flag = 1;
- break;
- case 'r':
- replace_flag = 1;
- break;
- case 'v':
- do_debug = 1;
- break;
-
- case 'D':
- if (strcasecmp(optarg, "s2c") == 0)
- direction = S2C;
- else if (strcasecmp(optarg, "c2s") == 0)
- direction = C2S;
- else
- badusage("Invalid direction (-D)");
- break;
- case 'f':
- data_path = optarg;
- break;
- case 'K':
- kex = optarg;
- break;
- case 'k':
- kpath = optarg;
- break;
- case 'i':
- packet_index = atoi(optarg);
- if (packet_index < 0)
- badusage("Invalid packet index");
- break;
- default:
- badusage("unsupported flag");
- }
- }
- argc -= optind;
- argv += optind;
-
- log_init(argv[0], do_debug ? SYSLOG_LEVEL_DEBUG3 : SYSLOG_LEVEL_INFO,
- SYSLOG_FACILITY_USER, 1);
-
- /* Must select a single mode */
- if ((count_flag + dump_flag + replace_flag) != 1)
- badusage("Must select one mode: -c, -d or -r");
- /* KEX type is mandatory */
- if (kex == NULL || !kex_names_valid(kex) || strchr(kex, ',') != NULL)
- badusage("Missing or invalid kex type (-K flag)");
- /* Valid key is mandatory */
- if (kpath == NULL)
- badusage("Missing private key (-k flag)");
- if ((fd = open(kpath, O_RDONLY)) == -1)
- err(1, "open %s", kpath);
- if ((r = sshkey_load_private_type_fd(fd, KEY_UNSPEC, NULL,
- &key, NULL)) != 0)
- errx(1, "Unable to load key %s: %s", kpath, ssh_err(r));
- close(fd);
- /* XXX check that it is a private key */
- /* XXX support certificates */
- if (key == NULL || key->type == KEY_UNSPEC)
- badusage("Invalid key file (-k flag)");
-
- /* Replace (fuzz) mode */
- if (replace_flag) {
- if (packet_index == -1 || direction == -1 || data_path == NULL)
- badusage("Replace (-r) mode must specify direction "
- "(-D) packet index (-i) and data path (-f)");
- if ((r = sshbuf_load_file(data_path, &replace_data)) != 0)
- errx(1, "read %s: %s", data_path, ssh_err(r));
- }
-
- /* Dump mode */
- if (dump_flag) {
- if (packet_index == -1 || direction == -1 || data_path == NULL)
- badusage("Dump (-d) mode must specify direction "
- "(-D), packet index (-i) and data path (-f)");
- }
-
- /* Count mode needs no further flags */
-
- do_kex_with_key(kex, key, &c2s, &s2c,
- direction, packet_index,
- dump_flag ? data_path : NULL,
- replace_flag ? replace_data : NULL);
- sshkey_free(key);
- sshbuf_free(replace_data);
-
- if (count_flag) {
- printf("S2C: %d\n", s2c);
- printf("C2S: %d\n", c2s);
- }
-
- return 0;
-}
diff --git a/regress/misc/sk-dummy/fatal.c b/regress/misc/sk-dummy/fatal.c
index 7cdc74b97b57..c6e4b5d6fa71 100644
--- a/regress/misc/sk-dummy/fatal.c
+++ b/regress/misc/sk-dummy/fatal.c
@@ -1,20 +1,27 @@
/* public domain */
+#include "includes.h"
+
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
-void fatal(char *fmt, ...);
+#include "log.h"
void
-fatal(char *fmt, ...)
+sshfatal(const char *file, const char *func, int line, int showfunc,
+ LogLevel level, const char *suffix, const char *fmt, ...)
{
va_list ap;
+ if (showfunc)
+ fprintf(stderr, "%s: ", func);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
+ if (suffix != NULL)
+ fprintf(stderr, ": %s", suffix);
fputc('\n', stderr);
_exit(1);
}
diff --git a/regress/misc/sk-dummy/sk-dummy.c b/regress/misc/sk-dummy/sk-dummy.c
index bf1feec1537a..4003362d7960 100644
--- a/regress/misc/sk-dummy/sk-dummy.c
+++ b/regress/misc/sk-dummy/sk-dummy.c
@@ -51,6 +51,13 @@
# error SK API has changed, sk-dummy.c needs an update
#endif
+#ifdef SK_DUMMY_INTEGRATE
+# define sk_api_version ssh_sk_api_version
+# define sk_enroll ssh_sk_enroll
+# define sk_sign ssh_sk_sign
+# define sk_load_resident_keys ssh_sk_load_resident_keys
+#endif /* !SK_STANDALONE */
+
static void skdebug(const char *func, const char *fmt, ...)
__attribute__((__format__ (printf, 2, 3)));