1 /* 	$OpenBSD: test_kex.c,v 1.6 2021/12/14 21:25:27 deraadt Exp $ */
2 /*
3  * Regress test KEX
4  *
5  * Placed in the public domain
6  */
7 
8 #include <sys/types.h>
9 #include <stdio.h>
10 #include <stdint.h>
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include "test_helper.h"
15 
16 #include "ssherr.h"
17 #include "ssh_api.h"
18 #include "sshbuf.h"
19 #include "packet.h"
20 #include "myproposal.h"
21 
22 void kex_tests(void);
23 static int do_debug = 0;
24 
25 static int
26 do_send_and_receive(struct ssh *from, struct ssh *to)
27 {
28 	u_char type;
29 	size_t len;
30 	const u_char *buf;
31 	int r;
32 
33 	for (;;) {
34 		if ((r = ssh_packet_next(from, &type)) != 0) {
35 			fprintf(stderr, "ssh_packet_next: %s\n", ssh_err(r));
36 			return r;
37 		}
38 		if (type != 0)
39 			return 0;
40 		buf = ssh_output_ptr(from, &len);
41 		if (do_debug)
42 			printf("%zu", len);
43 		if (len == 0)
44 			return 0;
45 		if ((r = ssh_output_consume(from, len)) != 0 ||
46 		    (r = ssh_input_append(to, buf, len)) != 0)
47 			return r;
48 	}
49 }
50 
51 static void
52 run_kex(struct ssh *client, struct ssh *server)
53 {
54 	int r = 0;
55 
56 	while (!server->kex->done || !client->kex->done) {
57 		if (do_debug)
58 			printf(" S:");
59 		if ((r = do_send_and_receive(server, client)))
60 			break;
61 		if (do_debug)
62 			printf(" C:");
63 		if ((r = do_send_and_receive(client, server)))
64 			break;
65 	}
66 	if (do_debug)
67 		printf("done: %s\n", ssh_err(r));
68 	ASSERT_INT_EQ(r, 0);
69 	ASSERT_INT_EQ(server->kex->done, 1);
70 	ASSERT_INT_EQ(client->kex->done, 1);
71 }
72 
73 static void
74 do_kex_with_key(char *kex, int keytype, int bits)
75 {
76 	struct ssh *client = NULL, *server = NULL, *server2 = NULL;
77 	struct sshkey *private, *public;
78 	struct sshbuf *state;
79 	struct kex_params kex_params;
80 	char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
81 	char *keyname = NULL;
82 
83 	TEST_START("sshkey_generate");
84 	ASSERT_INT_EQ(sshkey_generate(keytype, bits, &private), 0);
85 	TEST_DONE();
86 
87 	TEST_START("sshkey_from_private");
88 	ASSERT_INT_EQ(sshkey_from_private(private, &public), 0);
89 	TEST_DONE();
90 
91 	TEST_START("ssh_init");
92 	memcpy(kex_params.proposal, myproposal, sizeof(myproposal));
93 	if (kex != NULL)
94 		kex_params.proposal[PROPOSAL_KEX_ALGS] = kex;
95 	keyname = strdup(sshkey_ssh_name(private));
96 	ASSERT_PTR_NE(keyname, NULL);
97 	kex_params.proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = keyname;
98 	ASSERT_INT_EQ(ssh_init(&client, 0, &kex_params), 0);
99 	ASSERT_INT_EQ(ssh_init(&server, 1, &kex_params), 0);
100 	ASSERT_PTR_NE(client, NULL);
101 	ASSERT_PTR_NE(server, NULL);
102 	TEST_DONE();
103 
104 	TEST_START("ssh_add_hostkey");
105 	ASSERT_INT_EQ(ssh_add_hostkey(server, private), 0);
106 	ASSERT_INT_EQ(ssh_add_hostkey(client, public), 0);
107 	TEST_DONE();
108 
109 	TEST_START("kex");
110 	run_kex(client, server);
111 	TEST_DONE();
112 
113 	TEST_START("rekeying client");
114 	ASSERT_INT_EQ(kex_send_kexinit(client), 0);
115 	run_kex(client, server);
116 	TEST_DONE();
117 
118 	TEST_START("rekeying server");
119 	ASSERT_INT_EQ(kex_send_kexinit(server), 0);
120 	run_kex(client, server);
121 	TEST_DONE();
122 
123 	TEST_START("ssh_packet_get_state");
124 	state = sshbuf_new();
125 	ASSERT_PTR_NE(state, NULL);
126 	ASSERT_INT_EQ(ssh_packet_get_state(server, state), 0);
127 	ASSERT_INT_GE(sshbuf_len(state), 1);
128 	TEST_DONE();
129 
130 	TEST_START("ssh_packet_set_state");
131 	server2 = NULL;
132 	ASSERT_INT_EQ(ssh_init(&server2, 1, NULL), 0);
133 	ASSERT_PTR_NE(server2, NULL);
134 	ASSERT_INT_EQ(ssh_add_hostkey(server2, private), 0);
135 	ASSERT_INT_EQ(ssh_packet_set_state(server2, state), 0);
136 	ASSERT_INT_EQ(sshbuf_len(state), 0);
137 	sshbuf_free(state);
138 	ASSERT_PTR_NE(server2->kex, NULL);
139 	/* XXX we need to set the callbacks */
140 	server2->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server;
141 	server2->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server;
142 	server2->kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
143 	server2->kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
144 	server2->kex->kex[KEX_ECDH_SHA2] = kex_gen_server;
145 	server2->kex->kex[KEX_C25519_SHA256] = kex_gen_server;
146 	server2->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server;
147 	server2->kex->load_host_public_key = server->kex->load_host_public_key;
148 	server2->kex->load_host_private_key = server->kex->load_host_private_key;
149 	server2->kex->sign = server->kex->sign;
150 	TEST_DONE();
151 
152 	TEST_START("rekeying server2");
153 	ASSERT_INT_EQ(kex_send_kexinit(server2), 0);
154 	run_kex(client, server2);
155 	ASSERT_INT_EQ(kex_send_kexinit(client), 0);
156 	run_kex(client, server2);
157 	TEST_DONE();
158 
159 	TEST_START("cleanup");
160 	sshkey_free(private);
161 	sshkey_free(public);
162 	ssh_free(client);
163 	ssh_free(server);
164 	ssh_free(server2);
165 	free(keyname);
166 	TEST_DONE();
167 }
168 
169 static void
170 do_kex(char *kex)
171 {
172 	do_kex_with_key(kex, KEY_RSA, 2048);
173 	do_kex_with_key(kex, KEY_DSA, 1024);
174 	do_kex_with_key(kex, KEY_ECDSA, 256);
175 	do_kex_with_key(kex, KEY_ED25519, 256);
176 }
177 
178 void
179 kex_tests(void)
180 {
181 	do_kex("curve25519-sha256@libssh.org");
182 	do_kex("ecdh-sha2-nistp256");
183 	do_kex("ecdh-sha2-nistp384");
184 	do_kex("ecdh-sha2-nistp521");
185 	do_kex("diffie-hellman-group-exchange-sha256");
186 	do_kex("diffie-hellman-group-exchange-sha1");
187 	do_kex("diffie-hellman-group14-sha1");
188 	do_kex("diffie-hellman-group1-sha1");
189 	do_kex("sntrup761x25519-sha512@openssh.com");
190 }
191