xref: /openbsd-src/regress/usr.bin/ssh/unittests/kex/test_kex.c (revision de2798f9cca94f613d42ec59629c4416e95b2df4)
1*de2798f9Sdjm /* 	$OpenBSD: test_kex.c,v 1.9 2024/09/09 03:13:39 djm Exp $ */
234c9c041Smarkus /*
334c9c041Smarkus  * Regress test KEX
434c9c041Smarkus  *
534c9c041Smarkus  * Placed in the public domain
634c9c041Smarkus  */
734c9c041Smarkus 
834c9c041Smarkus #include <sys/types.h>
934c9c041Smarkus #include <stdio.h>
1034c9c041Smarkus #include <stdint.h>
1134c9c041Smarkus #include <stdlib.h>
1234c9c041Smarkus #include <string.h>
1334c9c041Smarkus 
1434c9c041Smarkus #include "test_helper.h"
1534c9c041Smarkus 
1634c9c041Smarkus #include "ssherr.h"
1734c9c041Smarkus #include "ssh_api.h"
1834c9c041Smarkus #include "sshbuf.h"
1934c9c041Smarkus #include "packet.h"
2034c9c041Smarkus #include "myproposal.h"
2151f4be5aSdjm #include "log.h"
2234c9c041Smarkus 
2334c9c041Smarkus void kex_tests(void);
2434c9c041Smarkus static int do_debug = 0;
2534c9c041Smarkus 
2634c9c041Smarkus static int
2734c9c041Smarkus do_send_and_receive(struct ssh *from, struct ssh *to)
2834c9c041Smarkus {
2934c9c041Smarkus 	u_char type;
3034c9c041Smarkus 	size_t len;
3134c9c041Smarkus 	const u_char *buf;
3234c9c041Smarkus 	int r;
3334c9c041Smarkus 
3434c9c041Smarkus 	for (;;) {
3534c9c041Smarkus 		if ((r = ssh_packet_next(from, &type)) != 0) {
3634c9c041Smarkus 			fprintf(stderr, "ssh_packet_next: %s\n", ssh_err(r));
3734c9c041Smarkus 			return r;
3834c9c041Smarkus 		}
3934c9c041Smarkus 		if (type != 0)
4034c9c041Smarkus 			return 0;
4134c9c041Smarkus 		buf = ssh_output_ptr(from, &len);
4234c9c041Smarkus 		if (do_debug)
4334c9c041Smarkus 			printf("%zu", len);
4434c9c041Smarkus 		if (len == 0)
4534c9c041Smarkus 			return 0;
4634c9c041Smarkus 		if ((r = ssh_output_consume(from, len)) != 0 ||
4734c9c041Smarkus 		    (r = ssh_input_append(to, buf, len)) != 0)
4834c9c041Smarkus 			return r;
4934c9c041Smarkus 	}
5034c9c041Smarkus }
5134c9c041Smarkus 
5234c9c041Smarkus static void
5334c9c041Smarkus run_kex(struct ssh *client, struct ssh *server)
5434c9c041Smarkus {
5534c9c041Smarkus 	int r = 0;
5634c9c041Smarkus 
5734c9c041Smarkus 	while (!server->kex->done || !client->kex->done) {
5834c9c041Smarkus 		if (do_debug)
5934c9c041Smarkus 			printf(" S:");
6034c9c041Smarkus 		if ((r = do_send_and_receive(server, client)))
6134c9c041Smarkus 			break;
6234c9c041Smarkus 		if (do_debug)
6334c9c041Smarkus 			printf(" C:");
6434c9c041Smarkus 		if ((r = do_send_and_receive(client, server)))
6534c9c041Smarkus 			break;
6634c9c041Smarkus 	}
6734c9c041Smarkus 	if (do_debug)
6834c9c041Smarkus 		printf("done: %s\n", ssh_err(r));
6934c9c041Smarkus 	ASSERT_INT_EQ(r, 0);
7034c9c041Smarkus 	ASSERT_INT_EQ(server->kex->done, 1);
7134c9c041Smarkus 	ASSERT_INT_EQ(client->kex->done, 1);
7234c9c041Smarkus }
7334c9c041Smarkus 
7434c9c041Smarkus static void
7534c9c041Smarkus do_kex_with_key(char *kex, int keytype, int bits)
7634c9c041Smarkus {
7734c9c041Smarkus 	struct ssh *client = NULL, *server = NULL, *server2 = NULL;
7834c9c041Smarkus 	struct sshkey *private, *public;
7934c9c041Smarkus 	struct sshbuf *state;
8034c9c041Smarkus 	struct kex_params kex_params;
8134c9c041Smarkus 	char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
82a87f2307Smarkus 	char *keyname = NULL;
8334c9c041Smarkus 
8434c9c041Smarkus 	TEST_START("sshkey_generate");
8534c9c041Smarkus 	ASSERT_INT_EQ(sshkey_generate(keytype, bits, &private), 0);
8634c9c041Smarkus 	TEST_DONE();
8734c9c041Smarkus 
8834c9c041Smarkus 	TEST_START("sshkey_from_private");
8934c9c041Smarkus 	ASSERT_INT_EQ(sshkey_from_private(private, &public), 0);
9034c9c041Smarkus 	TEST_DONE();
9134c9c041Smarkus 
9234c9c041Smarkus 	TEST_START("ssh_init");
9334c9c041Smarkus 	memcpy(kex_params.proposal, myproposal, sizeof(myproposal));
9434c9c041Smarkus 	if (kex != NULL)
9534c9c041Smarkus 		kex_params.proposal[PROPOSAL_KEX_ALGS] = kex;
96a87f2307Smarkus 	keyname = strdup(sshkey_ssh_name(private));
97a87f2307Smarkus 	ASSERT_PTR_NE(keyname, NULL);
98a87f2307Smarkus 	kex_params.proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = keyname;
9934c9c041Smarkus 	ASSERT_INT_EQ(ssh_init(&client, 0, &kex_params), 0);
10034c9c041Smarkus 	ASSERT_INT_EQ(ssh_init(&server, 1, &kex_params), 0);
10134c9c041Smarkus 	ASSERT_PTR_NE(client, NULL);
10234c9c041Smarkus 	ASSERT_PTR_NE(server, NULL);
10334c9c041Smarkus 	TEST_DONE();
10434c9c041Smarkus 
10534c9c041Smarkus 	TEST_START("ssh_add_hostkey");
10634c9c041Smarkus 	ASSERT_INT_EQ(ssh_add_hostkey(server, private), 0);
10734c9c041Smarkus 	ASSERT_INT_EQ(ssh_add_hostkey(client, public), 0);
10834c9c041Smarkus 	TEST_DONE();
10934c9c041Smarkus 
11034c9c041Smarkus 	TEST_START("kex");
11134c9c041Smarkus 	run_kex(client, server);
11234c9c041Smarkus 	TEST_DONE();
11334c9c041Smarkus 
11434c9c041Smarkus 	TEST_START("rekeying client");
11534c9c041Smarkus 	ASSERT_INT_EQ(kex_send_kexinit(client), 0);
11634c9c041Smarkus 	run_kex(client, server);
11734c9c041Smarkus 	TEST_DONE();
11834c9c041Smarkus 
11934c9c041Smarkus 	TEST_START("rekeying server");
12034c9c041Smarkus 	ASSERT_INT_EQ(kex_send_kexinit(server), 0);
12134c9c041Smarkus 	run_kex(client, server);
12234c9c041Smarkus 	TEST_DONE();
12334c9c041Smarkus 
12434c9c041Smarkus 	TEST_START("ssh_packet_get_state");
12534c9c041Smarkus 	state = sshbuf_new();
12634c9c041Smarkus 	ASSERT_PTR_NE(state, NULL);
12734c9c041Smarkus 	ASSERT_INT_EQ(ssh_packet_get_state(server, state), 0);
12834c9c041Smarkus 	ASSERT_INT_GE(sshbuf_len(state), 1);
12934c9c041Smarkus 	TEST_DONE();
13034c9c041Smarkus 
13134c9c041Smarkus 	TEST_START("ssh_packet_set_state");
13234c9c041Smarkus 	server2 = NULL;
13334c9c041Smarkus 	ASSERT_INT_EQ(ssh_init(&server2, 1, NULL), 0);
13434c9c041Smarkus 	ASSERT_PTR_NE(server2, NULL);
13534c9c041Smarkus 	ASSERT_INT_EQ(ssh_add_hostkey(server2, private), 0);
13634c9c041Smarkus 	ASSERT_INT_EQ(ssh_packet_set_state(server2, state), 0);
13734c9c041Smarkus 	ASSERT_INT_EQ(sshbuf_len(state), 0);
13834c9c041Smarkus 	sshbuf_free(state);
13934c9c041Smarkus 	ASSERT_PTR_NE(server2->kex, NULL);
14034c9c041Smarkus 	/* XXX we need to set the callbacks */
14148e89353Sdjm 	server2->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server;
14248e89353Sdjm 	server2->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server;
14334c9c041Smarkus 	server2->kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
14434c9c041Smarkus 	server2->kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
14548e89353Sdjm 	server2->kex->kex[KEX_ECDH_SHA2] = kex_gen_server;
14648e89353Sdjm 	server2->kex->kex[KEX_C25519_SHA256] = kex_gen_server;
147df66acdcSdjm 	server2->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server;
148*de2798f9Sdjm 	server2->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server;
14934c9c041Smarkus 	server2->kex->load_host_public_key = server->kex->load_host_public_key;
15034c9c041Smarkus 	server2->kex->load_host_private_key = server->kex->load_host_private_key;
15134c9c041Smarkus 	server2->kex->sign = server->kex->sign;
15234c9c041Smarkus 	TEST_DONE();
15334c9c041Smarkus 
15434c9c041Smarkus 	TEST_START("rekeying server2");
15534c9c041Smarkus 	ASSERT_INT_EQ(kex_send_kexinit(server2), 0);
15634c9c041Smarkus 	run_kex(client, server2);
15734c9c041Smarkus 	ASSERT_INT_EQ(kex_send_kexinit(client), 0);
15834c9c041Smarkus 	run_kex(client, server2);
15934c9c041Smarkus 	TEST_DONE();
16034c9c041Smarkus 
16134c9c041Smarkus 	TEST_START("cleanup");
16234c9c041Smarkus 	sshkey_free(private);
16334c9c041Smarkus 	sshkey_free(public);
16434c9c041Smarkus 	ssh_free(client);
16534c9c041Smarkus 	ssh_free(server);
16634c9c041Smarkus 	ssh_free(server2);
167a87f2307Smarkus 	free(keyname);
16834c9c041Smarkus 	TEST_DONE();
16934c9c041Smarkus }
17034c9c041Smarkus 
17134c9c041Smarkus static void
17234c9c041Smarkus do_kex(char *kex)
17334c9c041Smarkus {
17434c9c041Smarkus 	do_kex_with_key(kex, KEY_RSA, 2048);
17533ada582Sdjm #ifdef WITH_DSA
17634c9c041Smarkus 	do_kex_with_key(kex, KEY_DSA, 1024);
17733ada582Sdjm #endif
17834c9c041Smarkus 	do_kex_with_key(kex, KEY_ECDSA, 256);
17934c9c041Smarkus 	do_kex_with_key(kex, KEY_ED25519, 256);
18034c9c041Smarkus }
18134c9c041Smarkus 
18234c9c041Smarkus void
18334c9c041Smarkus kex_tests(void)
18434c9c041Smarkus {
18551f4be5aSdjm #if 0
18651f4be5aSdjm         log_init("test_kex", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 1);
18751f4be5aSdjm #endif
18834c9c041Smarkus 	do_kex("curve25519-sha256@libssh.org");
18934c9c041Smarkus 	do_kex("ecdh-sha2-nistp256");
19034c9c041Smarkus 	do_kex("ecdh-sha2-nistp384");
19134c9c041Smarkus 	do_kex("ecdh-sha2-nistp521");
19234c9c041Smarkus 	do_kex("diffie-hellman-group-exchange-sha256");
19334c9c041Smarkus 	do_kex("diffie-hellman-group-exchange-sha1");
19434c9c041Smarkus 	do_kex("diffie-hellman-group14-sha1");
19534c9c041Smarkus 	do_kex("diffie-hellman-group1-sha1");
196df66acdcSdjm 	do_kex("sntrup761x25519-sha512@openssh.com");
197*de2798f9Sdjm 	do_kex("mlkem768x25519-sha256");
19834c9c041Smarkus }
199