1 // libfuzzer driver for key exchange fuzzing.
2 
3 
4 #include <sys/types.h>
5 #include <sys/param.h>
6 #include <stdio.h>
7 #include <stdint.h>
8 #include <stdlib.h>
9 #include <string.h>
10 
11 extern "C" {
12 
13 #include "includes.h"
14 #include "ssherr.h"
15 #include "ssh_api.h"
16 #include "sshbuf.h"
17 #include "packet.h"
18 #include "myproposal.h"
19 #include "xmalloc.h"
20 #include "authfile.h"
21 #include "log.h"
22 
23 // Define if you want to generate traces.
24 /* #define STANDALONE 1 */
25 
26 #define PRIV_RSA \
27 "-----BEGIN OPENSSH PRIVATE KEY-----\n"\
28 "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn\n"\
29 "NhAAAAAwEAAQAAAQEA3+epf+VGKoGPaAZXrf6S0cyumQnddkGBnVFX0A5eh37RtLug0qY5\n"\
30 "thxsBUbGGVr9mTd2QXwLujBwYg5l1MP/Fmg+5312Zgx9pHmS+qKULbar0hlNgptNEb+aNU\n"\
31 "d3o9qg3aXqXm7+ZnjAV05ef/mxNRN2ZvuEkw7cRppTJcbBI+vF3lXuCXnX2klDI95Gl2AW\n"\
32 "3WHRtanqLHZXuBkjjRBDKc7MUq/GP1hmLiAd95dvU7fZjRlIEsP84zGEI1Fb0L/kmPHcOt\n"\
33 "iVfHft8CtmC9v6+94JrOiPBBNScV+dyrgAGPsdKdr/1vIpQmCNiI8s3PCiD8J7ZiBaYm0I\n"\
34 "8fq5G/qnUwAAA7ggw2dXIMNnVwAAAAdzc2gtcnNhAAABAQDf56l/5UYqgY9oBlet/pLRzK\n"\
35 "6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZm\n"\
36 "DH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGml\n"\
37 "MlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29T\n"\
38 "t9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v\n"\
39 "/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdTAAAAAwEAAQAAAQEArWm5B4tFasppjUHM\n"\
40 "SsAuajtCxtizI1Hc10EW59cZM4vvUzE2f6+qZvdgWj3UU/L7Et23w0QVuSCnCerox379ZB\n"\
41 "ddEOFFAAiQjwBx65hbd4RRUymxtIQfjq18++LcMJW1nbVQ7c69ThQbtALIggmbS+ZE/8Gx\n"\
42 "jkwmIrCH0Ww8TlpsPe+mNHuyNk7UEZoXLm22lNLqq5qkIL5JgT6M2iNJpMOJy9/CKi6kO4\n"\
43 "JPuVwjdG4C5pBPaMN3KJ1IvAlSlLGNaXnfXcn85gWfsCjsZmH3liey2NJamqp/w83BrKUg\n"\
44 "YZvMR2qeWZaKkFTahpzN5KRK1BFeB37O0P84Dzh1biDX8QAAAIEAiWXW8ePYFwLpa2mFIh\n"\
45 "VvRTdcrN70rVK5eWVaL3pyS4vGA56Jixq86dHveOnbSY+iNb1jQidtXc8SWUt2wtHqZ32h\n"\
46 "Lji9/hMSKqe9SEP3xvDRDmUJqsVw0ySyrFrzm4160QY6RKU3CIQCVFslMZ9fxmrfZ/hxoU\n"\
47 "0X3FVsxmC4+kwAAACBAPOc1YERpV6PjANBrGR+1o1RCdACbm5myc42QzSNIaOZmgrYs+Gt\n"\
48 "7+EcoqSdbJzHJNCNQfF+A+vjbIkFiuZqq/5wwr59qXx5OAlijLB/ywwKmTWq6lp//Zxny+\n"\
49 "ka3sIGNO14eQvmxNDnlLL+RIZleCTEKBXSW6CZhr+uHMZFKKMtAAAAgQDrSkm+LbILB7H9\n"\
50 "jxEBZLhv53aAn4u81kFKQOJ7PzzpBGSoD12i7oIJu5siSD5EKDNVEr+SvCf0ISU3BuMpzl\n"\
51 "t3YrPrHRheOFhn5e3j0e//zB8rBC0DGB4CtTDdeh7rOXUL4K0pz+8wEpNkV62SWxhC6NRW\n"\
52 "I79JhtGkh+GtcnkEfwAAAAAB\n"\
53 "-----END OPENSSH PRIVATE KEY-----\n"
54 #define PUB_RSA \
55 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDf56l/5UYqgY9oBlet/pLRzK6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZmDH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGmlMlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29Tt9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdT"
56 #define PRIV_DSA \
57 "-----BEGIN OPENSSH PRIVATE KEY-----\n"\
58 "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsgAAAAdzc2gtZH\n"\
59 "NzAAAAgQCsGTfjpQ465EOkfQXJM9BOvfRQE0fqlykAls+ncz+T7hrbeScRu8xpwzsznJNm\n"\
60 "xlW8o6cUDiHmBJ5OHgamUC9N7YJeU/6fnOAZifgN8mqK6k8pKHuje8ANOiYgHLl0yiASQA\n"\
61 "3//qMyzZ+W/hemoLSmLAbEqlfWVeyYx+wta1Vm+QAAABUAvWyehvUvdHvQxavYgS5p0t5Q\n"\
62 "d7UAAACBAIRA9Yy+f4Kzqpv/qICPO3zk42UuP7WAhSW2nCbQdLlCiSTxcjKgcvXNRckwJP\n"\
63 "44JjSHOtJy/AMtJrPIbLYG6KuWTdBlEHFiG6DafvLG+qPMSL2bPjXTOhuOMbCHIZ+5WBkW\n"\
64 "THeG/Nv11iI01Of9V6tXkig23K370flkRkXFi9MdAAAAgCt6YUcQkNwG7B/e5M1FZsLP9O\n"\
65 "kVB3BwLAOjmWdHpyhu3HpwSJa3XLEvhXN0i6IVI2KgPo/2GtYA6rHt14L+6u1pmhh8sAvQ\n"\
66 "ksp3qZB+xh/NP+hBqf0sbHX0yYbzKOvI5SCc/kKK6yagcBZOsubM/KC8TxyVgmD5c6WzYs\n"\
67 "h5TEpvAAAB2PHjRbbx40W2AAAAB3NzaC1kc3MAAACBAKwZN+OlDjrkQ6R9Bckz0E699FAT\n"\
68 "R+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4B\n"\
69 "mJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1r\n"\
70 "VWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS\n"\
71 "4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIb\n"\
72 "oNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRc\n"\
73 "WL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SL\n"\
74 "ohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJ\n"\
75 "z+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8AAAAUUA+OGldMi76ClO/sstpdbBUE\n"\
76 "lq8AAAAAAQI=\n"\
77 "-----END OPENSSH PRIVATE KEY-----\n"
78 #define PUB_DSA \
79 "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="
80 #define PRIV_ECDSA \
81 "-----BEGIN OPENSSH PRIVATE KEY-----\n"\
82 "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS\n"\
83 "1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTDJ0VlMv+0rguNzaJ1DF2KueHaxRSQ\n"\
84 "6LpIxGbulrg1a8RPbnMXwag5GcDiDllD2lDUJUuBEWyjXA0rZoZX35ELAAAAoE/Bbr5PwW\n"\
85 "6+AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43N\n"\
86 "onUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQ\n"\
87 "sAAAAhAIhE6hCID5oOm1TDktc++KFKyScjLifcZ6Cgv5xSSyLOAAAAAAECAwQFBgc=\n"\
88 "-----END OPENSSH PRIVATE KEY-----\n"
89 #define PUB_ECDSA \
90 "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43NonUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQs="
91 #define PRIV_ED25519 \
92 "-----BEGIN OPENSSH PRIVATE KEY-----\n"\
93 "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n"\
94 "QyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAIhWlP99VpT/\n"\
95 "fQAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAw\n"\
96 "AAAEDE1rlcMC0s0X3TKVZAOVavZOywwkXw8tO5dLObxaCMEDPQXmEVMVLmeFRyafKMVWgP\n"\
97 "Dkv8/uRBTwmcEDatZzMDAAAAAAECAwQF\n"\
98 "-----END OPENSSH PRIVATE KEY-----\n"
99 #define PUB_ED25519 \
100 "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMD"
101 
102 static int prepare_key(struct shared_state *st, int keytype, int bits);
103 
104 struct shared_state {
105 	size_t nkeys;
106 	struct sshkey **privkeys, **pubkeys;
107 };
108 
109 struct test_state {
110 	struct sshbuf *smsgs, *cmsgs; /* output, for standalone mode */
111 	struct sshbuf *sin, *cin; /* input; setup per-test in do_kex_with_key */
112 	struct sshbuf *s_template, *c_template; /* main copy of input */
113 };
114 
115 static int
116 do_send_and_receive(struct ssh *from, struct ssh *to,
117     struct sshbuf *store, int clobber, size_t *n)
118 {
119 	u_char type;
120 	size_t len;
121 	const u_char *buf;
122 	int r;
123 
124 	for (*n = 0;; (*n)++) {
125 		if ((r = ssh_packet_next(from, &type)) != 0) {
126 			debug_fr(r, "ssh_packet_next");
127 			return r;
128 		}
129 		if (type != 0)
130 			return 0;
131 		buf = ssh_output_ptr(from, &len);
132 		debug_f("%zu%s", len, clobber ? " ignore" : "");
133 		if (len == 0)
134 			return 0;
135 		if ((r = ssh_output_consume(from, len)) != 0) {
136 			debug_fr(r, "ssh_output_consume");
137 			return r;
138 		}
139 		if (store != NULL && (r = sshbuf_put(store, buf, len)) != 0) {
140 			debug_fr(r, "sshbuf_put");
141 			return r;
142 		}
143 		if (!clobber && (r = ssh_input_append(to, buf, len)) != 0) {
144 			debug_fr(r, "ssh_input_append");
145 			return r;
146 		}
147 	}
148 }
149 
150 static int
151 run_kex(struct test_state *ts, struct ssh *client, struct ssh *server)
152 {
153 	int r = 0;
154 	size_t cn, sn;
155 
156 	/* If fuzzing, replace server/client input */
157 	if (ts->sin != NULL) {
158 		if ((r = ssh_input_append(server, sshbuf_ptr(ts->sin),
159 		    sshbuf_len(ts->sin))) != 0) {
160 			error_fr(r, "ssh_input_append");
161 			return r;
162 		}
163 		sshbuf_reset(ts->sin);
164 	}
165 	if (ts->cin != NULL) {
166 		if ((r = ssh_input_append(client, sshbuf_ptr(ts->cin),
167 		    sshbuf_len(ts->cin))) != 0) {
168 			error_fr(r, "ssh_input_append");
169 			return r;
170 		}
171 		sshbuf_reset(ts->cin);
172 	}
173 	while (!server->kex->done || !client->kex->done) {
174 		cn = sn = 0;
175 		debug_f("S:");
176 		if ((r = do_send_and_receive(server, client,
177 		    ts->smsgs, ts->cin != NULL, &sn)) != 0) {
178 			debug_fr(r, "S->C");
179 			break;
180 		}
181 		debug_f("C:");
182 		if ((r = do_send_and_receive(client, server,
183 		    ts->cmsgs, ts->sin != NULL, &cn)) != 0) {
184 			debug_fr(r, "C->S");
185 			break;
186 		}
187 		if (cn == 0 && sn == 0) {
188 			debug_f("kex stalled");
189 			r = SSH_ERR_PROTOCOL_ERROR;
190 			break;
191 		}
192 	}
193 	debug_fr(r, "done");
194 	return r;
195 }
196 
197 static void
198 store_key(struct shared_state *st, struct sshkey *pubkey,
199     struct sshkey *privkey)
200 {
201 	if (st == NULL || pubkey->type < 0 || pubkey->type > INT_MAX ||
202 	    privkey->type != pubkey->type ||
203 	    ((size_t)pubkey->type < st->nkeys &&
204 	     st->pubkeys[pubkey->type] != NULL))
205 		abort();
206 	if ((size_t)pubkey->type >= st->nkeys) {
207 		st->pubkeys = (struct sshkey **)xrecallocarray(st->pubkeys,
208 		    st->nkeys, pubkey->type + 1, sizeof(*st->pubkeys));
209 		st->privkeys = (struct sshkey **)xrecallocarray(st->privkeys,
210 		    st->nkeys, privkey->type + 1, sizeof(*st->privkeys));
211 		st->nkeys = privkey->type + 1;
212 	}
213 	debug_f("store %s at %d", sshkey_ssh_name(pubkey), pubkey->type);
214 	st->pubkeys[pubkey->type] = pubkey;
215 	st->privkeys[privkey->type] = privkey;
216 }
217 
218 static int
219 prepare_keys(struct shared_state *st)
220 {
221 	if (prepare_key(st, KEY_RSA, 2048) != 0 ||
222 	    prepare_key(st, KEY_DSA, 1024) != 0 ||
223 	    prepare_key(st, KEY_ECDSA, 256) != 0 ||
224 	    prepare_key(st, KEY_ED25519, 256) != 0) {
225 		error_f("key prepare failed");
226 		return -1;
227 	}
228 	return 0;
229 }
230 
231 static struct sshkey *
232 get_pubkey(struct shared_state *st, int keytype)
233 {
234 	if (st == NULL || keytype < 0 || (size_t)keytype >= st->nkeys ||
235 	    st->pubkeys == NULL || st->pubkeys[keytype] == NULL)
236 		abort();
237 	return st->pubkeys[keytype];
238 }
239 
240 static struct sshkey *
241 get_privkey(struct shared_state *st, int keytype)
242 {
243 	if (st == NULL || keytype < 0 || (size_t)keytype >= st->nkeys ||
244 	    st->privkeys == NULL || st->privkeys[keytype] == NULL)
245 		abort();
246 	return st->privkeys[keytype];
247 }
248 
249 static int
250 do_kex_with_key(struct shared_state *st, struct test_state *ts,
251     const char *kex, int keytype)
252 {
253 	struct ssh *client = NULL, *server = NULL;
254 	struct sshkey *privkey = NULL, *pubkey = NULL;
255 	struct sshbuf *state = NULL;
256 	struct kex_params kex_params;
257 	const char *ccp, *proposal[PROPOSAL_MAX] = { KEX_CLIENT };
258 	char *myproposal[PROPOSAL_MAX] = {0}, *keyname = NULL;
259 	int i, r;
260 
261 	ts->cin = ts->sin = NULL;
262 	if (ts->c_template != NULL &&
263 	    (ts->cin = sshbuf_fromb(ts->c_template)) == NULL)
264 		abort();
265 	if (ts->s_template != NULL &&
266 	    (ts->sin = sshbuf_fromb(ts->s_template)) == NULL)
267 		abort();
268 
269 	pubkey = get_pubkey(st, keytype);
270 	privkey = get_privkey(st, keytype);
271 	keyname = xstrdup(sshkey_ssh_name(privkey));
272 	if (ts->cin != NULL) {
273 		debug_f("%s %s clobber client %zu", kex, keyname,
274 		    sshbuf_len(ts->cin));
275 	} else if (ts->sin != NULL) {
276 		debug_f("%s %s clobber server %zu", kex, keyname,
277 		    sshbuf_len(ts->sin));
278 	} else
279 		debug_f("%s %s noclobber", kex, keyname);
280 
281 	for (i = 0; i < PROPOSAL_MAX; i++) {
282 		ccp = proposal[i];
283 #ifdef CIPHER_NONE_AVAIL
284 		if (i == PROPOSAL_ENC_ALGS_CTOS || i == PROPOSAL_ENC_ALGS_STOC)
285 			ccp = "none";
286 #endif
287 		if (i == PROPOSAL_SERVER_HOST_KEY_ALGS)
288 			ccp = keyname;
289 		else if (i == PROPOSAL_KEX_ALGS && kex != NULL)
290 			ccp = kex;
291 		if ((myproposal[i] = strdup(ccp)) == NULL) {
292 			error_f("strdup prop %d", i);
293 			goto fail;
294 		}
295 	}
296 	memcpy(kex_params.proposal, myproposal, sizeof(myproposal));
297 	if ((r = ssh_init(&client, 0, &kex_params)) != 0) {
298 		error_fr(r, "init client");
299 		goto fail;
300 	}
301 	if ((r = ssh_init(&server, 1, &kex_params)) != 0) {
302 		error_fr(r, "init server");
303 		goto fail;
304 	}
305 	if ((r = ssh_add_hostkey(server, privkey)) != 0 ||
306 	    (r = ssh_add_hostkey(client, pubkey)) != 0) {
307 		error_fr(r, "add hostkeys");
308 		goto fail;
309 	}
310 	if ((r = run_kex(ts, client, server)) != 0) {
311 		error_fr(r, "kex");
312 		goto fail;
313 	}
314 	/* XXX rekex, set_state, etc */
315  fail:
316 	for (i = 0; i < PROPOSAL_MAX; i++)
317 		free(myproposal[i]);
318 	sshbuf_free(ts->sin);
319 	sshbuf_free(ts->cin);
320 	sshbuf_free(state);
321 	ssh_free(client);
322 	ssh_free(server);
323 	free(keyname);
324 	return r;
325 }
326 
327 static int
328 prepare_key(struct shared_state *st, int kt, int bits)
329 {
330 	const char *pubstr = NULL;
331 	const char *privstr = NULL;
332 	char *tmp, *cp;
333 	struct sshkey *privkey = NULL, *pubkey = NULL;
334 	struct sshbuf *b = NULL;
335 	int r;
336 
337 	switch (kt) {
338 	case KEY_RSA:
339 		pubstr = PUB_RSA;
340 		privstr = PRIV_RSA;
341 		break;
342 	case KEY_DSA:
343 		pubstr = PUB_DSA;
344 		privstr = PRIV_DSA;
345 		break;
346 	case KEY_ECDSA:
347 		pubstr = PUB_ECDSA;
348 		privstr = PRIV_ECDSA;
349 		break;
350 	case KEY_ED25519:
351 		pubstr = PUB_ED25519;
352 		privstr = PRIV_ED25519;
353 		break;
354 	default:
355 		abort();
356 	}
357 	if ((b = sshbuf_from(privstr, strlen(privstr))) == NULL)
358 		abort();
359 	if ((r = sshkey_parse_private_fileblob(b, "", &privkey, NULL)) != 0) {
360 		error_fr(r, "priv %d", kt);
361 		abort();
362 	}
363 	sshbuf_free(b);
364 	tmp = cp = xstrdup(pubstr);
365 	if ((pubkey = sshkey_new(KEY_UNSPEC)) == NULL)
366 		abort();
367 	if ((r = sshkey_read(pubkey, &cp)) != 0) {
368 		error_fr(r, "pub %d", kt);
369 		abort();
370 	}
371 	free(tmp);
372 
373 	store_key(st, pubkey, privkey);
374 	return 0;
375 }
376 
377 #if defined(STANDALONE)
378 
379 #if 0 /* use this if generating new keys to embed above */
380 static int
381 prepare_key(struct shared_state *st, int keytype, int bits)
382 {
383 	struct sshkey *privkey = NULL, *pubkey = NULL;
384 	int r;
385 
386 	if ((r = sshkey_generate(keytype, bits, &privkey)) != 0) {
387 		error_fr(r, "generate");
388 		abort();
389 	}
390 	if ((r = sshkey_from_private(privkey, &pubkey)) != 0) {
391 		error_fr(r, "make pubkey");
392 		abort();
393 	}
394 	store_key(st, pubkey, privkey);
395 	return 0;
396 }
397 #endif
398 
399 int main(void)
400 {
401 	static struct shared_state *st;
402 	struct test_state *ts;
403 	const int keytypes[] = { KEY_RSA, KEY_DSA, KEY_ECDSA, KEY_ED25519, -1 };
404 	const char *kextypes[] = {
405 		"sntrup761x25519-sha512@openssh.com",
406 		"curve25519-sha256@libssh.org",
407 		"ecdh-sha2-nistp256",
408 		"diffie-hellman-group1-sha1",
409 		"diffie-hellman-group-exchange-sha1",
410 		NULL,
411 	};
412 	int i, j;
413 	char *path;
414 	FILE *f;
415 
416 	log_init("kex_fuzz", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 1);
417 
418 	if (st == NULL) {
419 		st = (struct shared_state *)xcalloc(1, sizeof(*st));
420 		prepare_keys(st);
421 	}
422 	/* Run each kex method for each key and save client/server packets */
423 	for (i = 0; keytypes[i] != -1; i++) {
424 		for (j = 0; kextypes[j] != NULL; j++) {
425 			ts = (struct test_state *)xcalloc(1, sizeof(*ts));
426 			ts->smsgs = sshbuf_new();
427 			ts->cmsgs = sshbuf_new();
428 			do_kex_with_key(st, ts, kextypes[j], keytypes[i]);
429 			xasprintf(&path, "S2C-%s-%s",
430 			    kextypes[j], sshkey_type(st->pubkeys[keytypes[i]]));
431 			debug_f("%s", path);
432 			if ((f = fopen(path, "wb+")) == NULL)
433 				abort();
434 			if (fwrite(sshbuf_ptr(ts->smsgs), 1,
435 			    sshbuf_len(ts->smsgs), f) != sshbuf_len(ts->smsgs))
436 				abort();
437 			fclose(f);
438 			free(path);
439 			//sshbuf_dump(ts->smsgs, stderr);
440 			xasprintf(&path, "C2S-%s-%s",
441 			    kextypes[j], sshkey_type(st->pubkeys[keytypes[i]]));
442 			debug_f("%s", path);
443 			if ((f = fopen(path, "wb+")) == NULL)
444 				abort();
445 			if (fwrite(sshbuf_ptr(ts->cmsgs), 1,
446 			    sshbuf_len(ts->cmsgs), f) != sshbuf_len(ts->cmsgs))
447 				abort();
448 			fclose(f);
449 			free(path);
450 			//sshbuf_dump(ts->cmsgs, stderr);
451 			sshbuf_free(ts->smsgs);
452 			sshbuf_free(ts->cmsgs);
453 			free(ts);
454 		}
455 	}
456 	for (i = 0; keytypes[i] != -1; i++) {
457 		xasprintf(&path, "%s.priv",
458 		    sshkey_type(st->privkeys[keytypes[i]]));
459 		debug_f("%s", path);
460 		if (sshkey_save_private(st->privkeys[keytypes[i]], path,
461 		    "", "", SSHKEY_PRIVATE_OPENSSH, NULL, 0) != 0)
462 			abort();
463 		free(path);
464 		xasprintf(&path, "%s.pub",
465 		    sshkey_type(st->pubkeys[keytypes[i]]));
466 		debug_f("%s", path);
467 		if (sshkey_save_public(st->pubkeys[keytypes[i]], path, "") != 0)
468 			abort();
469 		free(path);
470 	}
471 }
472 #else /* !STANDALONE */
473 static void
474 do_kex(struct shared_state *st, struct test_state *ts, const char *kex)
475 {
476 	do_kex_with_key(st, ts, kex, KEY_RSA);
477 	do_kex_with_key(st, ts, kex, KEY_DSA);
478 	do_kex_with_key(st, ts, kex, KEY_ECDSA);
479 	do_kex_with_key(st, ts, kex, KEY_ED25519);
480 }
481 
482 static void
483 kex_tests(struct shared_state *st, struct test_state *ts)
484 {
485 	do_kex(st, ts, "sntrup761x25519-sha512@openssh.com");
486 	do_kex(st, ts, "curve25519-sha256@libssh.org");
487 	do_kex(st, ts, "ecdh-sha2-nistp256");
488 	do_kex(st, ts, "diffie-hellman-group1-sha1");
489 	do_kex(st, ts, "diffie-hellman-group-exchange-sha1");
490 }
491 
492 int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
493 {
494 	static struct shared_state *st;
495 	struct test_state *ts;
496 	u_char crbuf[SSH_MAX_PRE_BANNER_LINES * 4];
497 	u_char zbuf[4096] = {0};
498 	static LogLevel loglevel = SYSLOG_LEVEL_INFO;
499 
500 	if (st == NULL) {
501 		if (getenv("DEBUG") != NULL || getenv("KEX_FUZZ_DEBUG") != NULL)
502 			loglevel = SYSLOG_LEVEL_DEBUG3;
503 		log_init("kex_fuzz",
504 		    loglevel, SYSLOG_FACILITY_AUTH, 1);
505 		st = (struct shared_state *)xcalloc(1, sizeof(*st));
506 		prepare_keys(st);
507 	}
508 
509 	/* Ensure that we can complete (fail) banner exchange at least */
510 	memset(crbuf, '\n', sizeof(crbuf));
511 
512 	ts = (struct test_state *)xcalloc(1, sizeof(*ts));
513 	if ((ts->s_template = sshbuf_new()) == NULL ||
514 	    sshbuf_put(ts->s_template, data, size) != 0 ||
515 	    sshbuf_put(ts->s_template, crbuf, sizeof(crbuf)) != 0 ||
516 	    sshbuf_put(ts->s_template, zbuf, sizeof(zbuf)) != 0)
517 		abort();
518 	kex_tests(st, ts);
519 	sshbuf_free(ts->s_template);
520 	free(ts);
521 
522 	ts = (struct test_state *)xcalloc(1, sizeof(*ts));
523 	if ((ts->c_template = sshbuf_new()) == NULL ||
524 	    sshbuf_put(ts->c_template, data, size) != 0 ||
525 	    sshbuf_put(ts->c_template, crbuf, sizeof(crbuf)) != 0 ||
526 	    sshbuf_put(ts->c_template, zbuf, sizeof(zbuf)) != 0)
527 		abort();
528 	kex_tests(st, ts);
529 	sshbuf_free(ts->c_template);
530 	free(ts);
531 
532 	return 0;
533 }
534 #endif /* STANDALONE */
535 } /* extern "C" */
536