summaryrefslogtreecommitdiffstats
path: root/regress/unittests/kex
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--regress/unittests/kex/Makefile40
-rw-r--r--regress/unittests/kex/test_kex.c208
-rw-r--r--regress/unittests/kex/test_proposal.c83
-rw-r--r--regress/unittests/kex/tests.c16
4 files changed, 347 insertions, 0 deletions
diff --git a/regress/unittests/kex/Makefile b/regress/unittests/kex/Makefile
new file mode 100644
index 0000000..981affe
--- /dev/null
+++ b/regress/unittests/kex/Makefile
@@ -0,0 +1,40 @@
+# $OpenBSD: Makefile,v 1.14 2023/02/02 12:12:52 djm Exp $
+
+PROG=test_kex
+SRCS=tests.c test_kex.c test_proposal.c
+
+# From usr.bin/ssh
+SRCS+=sshbuf-getput-basic.c sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c
+SRCS+=sshbuf-io.c atomicio.c sshkey.c authfile.c cipher.c log.c ssh-rsa.c
+SRCS+=ssh-dss.c 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+=addr.c addrmatch.c bitmap.c packet.c dispatch.c canohost.c ssh_api.c
+SRCS+=compat.c ed25519.c hash.c
+SRCS+=cipher-chachapoly.c chacha.c poly1305.c ssh-ecdsa-sk.c ssh-sk.c
+SRCS+=ssh-ed25519-sk.c sk-usbhid.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+= kexsntrup761x25519.c
+SRCS+= sntrup761.c
+SRCS+= utf8.c
+
+SRCS+=digest-openssl.c
+#SRCS+=digest-libc.c
+
+REGRESS_TARGETS=run-regress-${PROG}
+
+run-regress-${PROG}: ${PROG}
+ env ${TEST_ENV} ./${PROG}
+
+.include <bsd.regress.mk>
+
+LDADD+=-lz
diff --git a/regress/unittests/kex/test_kex.c b/regress/unittests/kex/test_kex.c
new file mode 100644
index 0000000..c26761e
--- /dev/null
+++ b/regress/unittests/kex/test_kex.c
@@ -0,0 +1,208 @@
+/* $OpenBSD: test_kex.c,v 1.6 2021/12/14 21:25:27 deraadt Exp $ */
+/*
+ * Regress test KEX
+ *
+ * Placed in the public domain
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <stdio.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include "../test_helper/test_helper.h"
+
+#include "ssherr.h"
+#include "ssh_api.h"
+#include "sshbuf.h"
+#include "packet.h"
+#include "myproposal.h"
+
+void kex_tests(void);
+static int do_debug = 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 (do_debug)
+ printf("%zu", len);
+ if (len == 0)
+ return 0;
+ if ((r = ssh_output_consume(from, len)) != 0 ||
+ (r = ssh_input_append(to, buf, len)) != 0)
+ return r;
+ }
+}
+
+static void
+run_kex(struct ssh *client, struct ssh *server)
+{
+ int r = 0;
+
+ while (!server->kex->done || !client->kex->done) {
+ if (do_debug)
+ printf(" S:");
+ if ((r = do_send_and_receive(server, client)))
+ break;
+ if (do_debug)
+ printf(" C:");
+ if ((r = do_send_and_receive(client, server)))
+ 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(char *kex, int keytype, int bits)
+{
+ struct ssh *client = NULL, *server = NULL, *server2 = NULL;
+ struct sshkey *private, *public;
+ struct sshbuf *state;
+ struct kex_params kex_params;
+ char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
+ char *keyname = NULL;
+
+ TEST_START("sshkey_generate");
+ ASSERT_INT_EQ(sshkey_generate(keytype, bits, &private), 0);
+ TEST_DONE();
+
+ TEST_START("sshkey_from_private");
+ ASSERT_INT_EQ(sshkey_from_private(private, &public), 0);
+ TEST_DONE();
+
+ TEST_START("ssh_init");
+ memcpy(kex_params.proposal, myproposal, sizeof(myproposal));
+ if (kex != NULL)
+ kex_params.proposal[PROPOSAL_KEX_ALGS] = kex;
+ keyname = strdup(sshkey_ssh_name(private));
+ 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_PTR_NE(client, NULL);
+ ASSERT_PTR_NE(server, NULL);
+ TEST_DONE();
+
+ TEST_START("ssh_add_hostkey");
+ ASSERT_INT_EQ(ssh_add_hostkey(server, private), 0);
+ ASSERT_INT_EQ(ssh_add_hostkey(client, public), 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");
+ server2 = NULL;
+ ASSERT_INT_EQ(ssh_init(&server2, 1, NULL), 0);
+ ASSERT_PTR_NE(server2, NULL);
+ ASSERT_INT_EQ(ssh_add_hostkey(server2, private), 0);
+ 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_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 /* OPENSSL_HAS_ECC */
+#endif /* WITH_OPENSSL */
+ server2->kex->kex[KEX_C25519_SHA256] = kex_gen_server;
+ server2->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = 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(private);
+ sshkey_free(public);
+ ssh_free(client);
+ ssh_free(server);
+ ssh_free(server2);
+ free(keyname);
+ TEST_DONE();
+}
+
+static void
+do_kex(char *kex)
+{
+#ifdef WITH_OPENSSL
+ do_kex_with_key(kex, KEY_RSA, 2048);
+ do_kex_with_key(kex, KEY_DSA, 1024);
+#ifdef OPENSSL_HAS_ECC
+ do_kex_with_key(kex, KEY_ECDSA, 256);
+#endif /* OPENSSL_HAS_ECC */
+#endif /* WITH_OPENSSL */
+ do_kex_with_key(kex, KEY_ED25519, 256);
+}
+
+void
+kex_tests(void)
+{
+ do_kex("curve25519-sha256@libssh.org");
+#ifdef WITH_OPENSSL
+#ifdef OPENSSL_HAS_ECC
+ do_kex("ecdh-sha2-nistp256");
+ do_kex("ecdh-sha2-nistp384");
+ do_kex("ecdh-sha2-nistp521");
+#endif /* OPENSSL_HAS_ECC */
+ do_kex("diffie-hellman-group-exchange-sha256");
+ do_kex("diffie-hellman-group-exchange-sha1");
+ do_kex("diffie-hellman-group14-sha1");
+ do_kex("diffie-hellman-group1-sha1");
+# ifdef USE_SNTRUP761X25519
+ do_kex("sntrup761x25519-sha512@openssh.com");
+# endif /* USE_SNTRUP761X25519 */
+#endif /* WITH_OPENSSL */
+}
diff --git a/regress/unittests/kex/test_proposal.c b/regress/unittests/kex/test_proposal.c
new file mode 100644
index 0000000..d6cf0f5
--- /dev/null
+++ b/regress/unittests/kex/test_proposal.c
@@ -0,0 +1,83 @@
+/* $OpenBSD: test_proposal.c,v 1.1 2023/02/02 12:12:52 djm Exp $ */
+/*
+ * Regress test KEX
+ *
+ * Placed in the public domain
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <signal.h>
+#include <stdio.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include "../test_helper/test_helper.h"
+
+#include "compat.h"
+#include "ssherr.h"
+#include "sshbuf.h"
+#include "kex.h"
+#include "packet.h"
+#include "xmalloc.h"
+
+void kex_proposal(void);
+
+#define CURVE25519 "curve25519-sha256@libssh.org"
+#define DHGEX1 "diffie-hellman-group-exchange-sha1"
+#define DHGEX256 "diffie-hellman-group-exchange-sha256"
+#define KEXALGOS CURVE25519","DHGEX256","DHGEX1
+void
+kex_proposal(void)
+{
+ size_t i;
+ struct ssh ssh;
+ char *result, *out, *in;
+ struct {
+ char *in; /* TODO: make this const */
+ char *out;
+ int compat;
+ } tests[] = {
+ { KEXALGOS, KEXALGOS, 0},
+ { KEXALGOS, DHGEX256","DHGEX1, SSH_BUG_CURVE25519PAD },
+ { KEXALGOS, CURVE25519, SSH_OLD_DHGEX },
+ { "a,"KEXALGOS, "a", SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX },
+ /* TODO: enable once compat_kex_proposal doesn't fatal() */
+ /* { KEXALGOS, "", SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX }, */
+ };
+
+ TEST_START("compat_kex_proposal");
+ for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
+ ssh.compat = tests[i].compat;
+ /* match entire string */
+ result = compat_kex_proposal(&ssh, tests[i].in);
+ ASSERT_STRING_EQ(result, tests[i].out);
+ free(result);
+ /* match at end */
+ in = kex_names_cat("a", tests[i].in);
+ out = kex_names_cat("a", tests[i].out);
+ result = compat_kex_proposal(&ssh, in);
+ ASSERT_STRING_EQ(result, out);
+ free(result); free(in); free(out);
+ /* match at start */
+ in = kex_names_cat(tests[i].in, "a");
+ out = kex_names_cat(tests[i].out, "a");
+ result = compat_kex_proposal(&ssh, in);
+ ASSERT_STRING_EQ(result, out);
+ free(result); free(in); free(out);
+ /* match in middle */
+ xasprintf(&in, "a,%s,b", tests[i].in);
+ if (*(tests[i].out) == '\0')
+ out = xstrdup("a,b");
+ else
+ xasprintf(&out, "a,%s,b", tests[i].out);
+ result = compat_kex_proposal(&ssh, in);
+ ASSERT_STRING_EQ(result, out);
+ free(result); free(in); free(out);
+ }
+ TEST_DONE();
+}
diff --git a/regress/unittests/kex/tests.c b/regress/unittests/kex/tests.c
new file mode 100644
index 0000000..2a83daf
--- /dev/null
+++ b/regress/unittests/kex/tests.c
@@ -0,0 +1,16 @@
+/* $OpenBSD: tests.c,v 1.2 2023/02/02 12:12:52 djm Exp $ */
+/*
+ * Placed in the public domain
+ */
+
+#include "../test_helper/test_helper.h"
+
+void kex_tests(void);
+void kex_proposal(void);
+
+void
+tests(void)
+{
+ kex_tests();
+ kex_proposal();
+}