summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2016-10-11 21:49:54 +0000
committerDamien Miller <djm@mindrot.org>2016-10-13 18:55:25 +1100
commit1723ec92eb485ce06b4cbf49712d21975d873909 (patch)
treeec8660501fca7aae241f434e2c3c6e4bcb6e1406
parent09f997893f109799cddbfce6d7e67f787045cbb2 (diff)
upstream commit
fix the KEX fuzzer - the previous method of obtaining the packet contents was broken. This now uses the new per-packet input hook, so it sees exact post-decrypt packets and doesn't have to pass packet integrity checks. ok markus@ Upstream-Regress-ID: 402fb6ffabd97de590e8e57b25788949dce8d2fd
-rw-r--r--regress/misc/kexfuzz/kexfuzz.c162
1 files changed, 103 insertions, 59 deletions
diff --git a/regress/misc/kexfuzz/kexfuzz.c b/regress/misc/kexfuzz/kexfuzz.c
index 8535980b0..67058027f 100644
--- a/regress/misc/kexfuzz/kexfuzz.c
+++ b/regress/misc/kexfuzz/kexfuzz.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: kexfuzz.c,v 1.2 2016/09/16 01:01:41 djm Exp $ */ 1/* $OpenBSD: kexfuzz.c,v 1.3 2016/10/11 21:49:54 djm Exp $ */
2/* 2/*
3 * Fuzz harness for KEX code 3 * Fuzz harness for KEX code
4 * 4 *
@@ -27,6 +27,7 @@
27#include "packet.h" 27#include "packet.h"
28#include "myproposal.h" 28#include "myproposal.h"
29#include "authfile.h" 29#include "authfile.h"
30#include "log.h"
30 31
31struct ssh *active_state = NULL; /* XXX - needed for linking */ 32struct ssh *active_state = NULL; /* XXX - needed for linking */
32 33
@@ -35,61 +36,93 @@ static int do_debug = 0;
35 36
36enum direction { S2C, C2S }; 37enum direction { S2C, C2S };
37 38
39struct hook_ctx {
40 struct ssh *client, *server, *server2;
41 int *c2s, *s2c;
42 int trigger_direction, packet_index;
43 const char *dump_path;
44 struct sshbuf *replace_data;
45};
46
38static int 47static int
39do_send_and_receive(struct ssh *from, struct ssh *to, int mydirection, 48packet_hook(struct ssh *ssh, struct sshbuf *packet, u_char *typep, void *_ctx)
40 int *packet_count, int trigger_direction, int packet_index, 49{
41 const char *dump_path, struct sshbuf *replace_data) 50 struct hook_ctx *ctx = (struct hook_ctx *)_ctx;
51 int mydirection = ssh == ctx->client ? S2C : C2S;
52 int *packet_count = mydirection == S2C ? ctx->s2c : ctx->c2s;
53 FILE *dumpfile;
54 int r;
55
56 if (do_debug) {
57 printf("%s packet %d type %u:\n",
58 mydirection == S2C ? "s2c" : "c2s",
59 *packet_count, *typep);
60 sshbuf_dump(packet, stdout);
61 }
62 if (mydirection == ctx->trigger_direction &&
63 ctx->packet_index == *packet_count) {
64 if (ctx->replace_data != NULL) {
65 sshbuf_reset(packet);
66 /* Type is first byte of packet */
67 if ((r = sshbuf_get_u8(ctx->replace_data,
68 typep)) != 0 ||
69 (r = sshbuf_putb(packet, ctx->replace_data)) != 0)
70 return r;
71 if (do_debug) {
72 printf("***** replaced packet type %u\n",
73 *typep);
74 sshbuf_dump(packet, stdout);
75 }
76 } else if (ctx->dump_path != NULL) {
77 if ((dumpfile = fopen(ctx->dump_path, "w+")) == NULL)
78 err(1, "fopen %s", ctx->dump_path);
79 /* Write { type, packet } */
80 if (fwrite(typep, 1, 1, dumpfile) != 1)
81 err(1, "fwrite type %s", ctx->dump_path);
82 if (sshbuf_len(packet) != 0 &&
83 fwrite(sshbuf_ptr(packet), sshbuf_len(packet),
84 1, dumpfile) != 1)
85 err(1, "fwrite body %s", ctx->dump_path);
86 if (do_debug) {
87 printf("***** dumped packet type %u len %zu\n",
88 *typep, sshbuf_len(packet));
89 }
90 fclose(dumpfile);
91 /* No point in continuing */
92 exit(0);
93 }
94 }
95 (*packet_count)++;
96 return 0;
97}
98
99static int
100do_send_and_receive(struct ssh *from, struct ssh *to)
42{ 101{
43 u_char type; 102 u_char type;
44 size_t len, olen; 103 size_t len;
45 const u_char *buf; 104 const u_char *buf;
46 int r; 105 int r;
47 FILE *dumpfile;
48 106
49 for (;;) { 107 for (;;) {
50 if ((r = ssh_packet_next(from, &type)) != 0) { 108 if ((r = ssh_packet_next(from, &type)) != 0) {
51 fprintf(stderr, "ssh_packet_next: %s\n", ssh_err(r)); 109 fprintf(stderr, "ssh_packet_next: %s\n", ssh_err(r));
52 return r; 110 return r;
53 } 111 }
112
54 if (type != 0) 113 if (type != 0)
55 return 0; 114 return 0;
56 buf = ssh_output_ptr(from, &len); 115 buf = ssh_output_ptr(from, &len);
57 olen = len;
58 if (do_debug) {
59 printf("%s packet %d type %u len %zu:\n",
60 mydirection == S2C ? "s2c" : "c2s",
61 *packet_count, type, len);
62 sshbuf_dump_data(buf, len, stdout);
63 }
64 if (mydirection == trigger_direction &&
65 packet_index == *packet_count) {
66 if (replace_data != NULL) {
67 buf = sshbuf_ptr(replace_data);
68 len = sshbuf_len(replace_data);
69 if (do_debug) {
70 printf("***** replaced packet "
71 "len %zu\n", len);
72 sshbuf_dump_data(buf, len, stdout);
73 }
74 } else if (dump_path != NULL) {
75 if ((dumpfile = fopen(dump_path, "w+")) == NULL)
76 err(1, "fopen %s", dump_path);
77 if (len != 0 &&
78 fwrite(buf, len, 1, dumpfile) != 1)
79 err(1, "fwrite %s", dump_path);
80 if (do_debug)
81 printf("***** dumped packet "
82 "len %zu\n", len);
83 fclose(dumpfile);
84 exit(0);
85 }
86 }
87 (*packet_count)++;
88 if (len == 0) 116 if (len == 0)
89 return 0; 117 return 0;
90 if ((r = ssh_input_append(to, buf, len)) != 0 || 118 if ((r = ssh_input_append(to, buf, len)) != 0) {
91 (r = ssh_output_consume(from, olen)) != 0) 119 debug("ssh_input_append: %s", ssh_err(r));
120 return r;
121 }
122 if ((r = ssh_output_consume(from, len)) != 0) {
123 debug("ssh_output_consume: %s", ssh_err(r));
92 return r; 124 return r;
125 }
93 } 126 }
94} 127}
95 128
@@ -141,19 +174,19 @@ const char *in_test = NULL;
141 174
142 175
143static void 176static void
144run_kex(struct ssh *client, struct ssh *server, int *s2c, int *c2s, 177run_kex(struct ssh *client, struct ssh *server)
145 int direction, int packet_index,
146 const char *dump_path, struct sshbuf *replace_data)
147{ 178{
148 int r = 0; 179 int r = 0;
149 180
150 while (!server->kex->done || !client->kex->done) { 181 while (!server->kex->done || !client->kex->done) {
151 if ((r = do_send_and_receive(server, client, S2C, s2c, 182 if ((r = do_send_and_receive(server, client)) != 0) {
152 direction, packet_index, dump_path, replace_data))) 183 debug("do_send_and_receive S2C: %s", ssh_err(r));
153 break; 184 break;
154 if ((r = do_send_and_receive(client, server, C2S, c2s, 185 }
155 direction, packet_index, dump_path, replace_data))) 186 if ((r = do_send_and_receive(client, server)) != 0) {
187 debug("do_send_and_receive C2S: %s", ssh_err(r));
156 break; 188 break;
189 }
157 } 190 }
158 if (do_debug) 191 if (do_debug)
159 printf("done: %s\n", ssh_err(r)); 192 printf("done: %s\n", ssh_err(r));
@@ -173,6 +206,7 @@ do_kex_with_key(const char *kex, struct sshkey *prvkey, int *c2s, int *s2c,
173 struct kex_params kex_params; 206 struct kex_params kex_params;
174 char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; 207 char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
175 char *keyname = NULL; 208 char *keyname = NULL;
209 struct hook_ctx hook_ctx;
176 210
177 TEST_START("sshkey_from_private"); 211 TEST_START("sshkey_from_private");
178 ASSERT_INT_EQ(sshkey_from_private(prvkey, &pubkey), 0); 212 ASSERT_INT_EQ(sshkey_from_private(prvkey, &pubkey), 0);
@@ -187,30 +221,42 @@ do_kex_with_key(const char *kex, struct sshkey *prvkey, int *c2s, int *s2c,
187 kex_params.proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = keyname; 221 kex_params.proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = keyname;
188 ASSERT_INT_EQ(ssh_init(&client, 0, &kex_params), 0); 222 ASSERT_INT_EQ(ssh_init(&client, 0, &kex_params), 0);
189 ASSERT_INT_EQ(ssh_init(&server, 1, &kex_params), 0); 223 ASSERT_INT_EQ(ssh_init(&server, 1, &kex_params), 0);
224 ASSERT_INT_EQ(ssh_init(&server2, 1, NULL), 0);
190 ASSERT_PTR_NE(client, NULL); 225 ASSERT_PTR_NE(client, NULL);
191 ASSERT_PTR_NE(server, NULL); 226 ASSERT_PTR_NE(server, NULL);
227 ASSERT_PTR_NE(server2, NULL);
192 TEST_DONE(); 228 TEST_DONE();
193 229
230 hook_ctx.c2s = c2s;
231 hook_ctx.s2c = s2c;
232 hook_ctx.trigger_direction = direction;
233 hook_ctx.packet_index = packet_index;
234 hook_ctx.dump_path = dump_path;
235 hook_ctx.replace_data = replace_data;
236 hook_ctx.client = client;
237 hook_ctx.server = server;
238 hook_ctx.server2 = server2;
239 ssh_packet_set_input_hook(client, packet_hook, &hook_ctx);
240 ssh_packet_set_input_hook(server, packet_hook, &hook_ctx);
241 ssh_packet_set_input_hook(server2, packet_hook, &hook_ctx);
242
194 TEST_START("ssh_add_hostkey"); 243 TEST_START("ssh_add_hostkey");
195 ASSERT_INT_EQ(ssh_add_hostkey(server, prvkey), 0); 244 ASSERT_INT_EQ(ssh_add_hostkey(server, prvkey), 0);
196 ASSERT_INT_EQ(ssh_add_hostkey(client, pubkey), 0); 245 ASSERT_INT_EQ(ssh_add_hostkey(client, pubkey), 0);
197 TEST_DONE(); 246 TEST_DONE();
198 247
199 TEST_START("kex"); 248 TEST_START("kex");
200 run_kex(client, server, s2c, c2s, direction, packet_index, 249 run_kex(client, server);
201 dump_path, replace_data);
202 TEST_DONE(); 250 TEST_DONE();
203 251
204 TEST_START("rekeying client"); 252 TEST_START("rekeying client");
205 ASSERT_INT_EQ(kex_send_kexinit(client), 0); 253 ASSERT_INT_EQ(kex_send_kexinit(client), 0);
206 run_kex(client, server, s2c, c2s, direction, packet_index, 254 run_kex(client, server);
207 dump_path, replace_data);
208 TEST_DONE(); 255 TEST_DONE();
209 256
210 TEST_START("rekeying server"); 257 TEST_START("rekeying server");
211 ASSERT_INT_EQ(kex_send_kexinit(server), 0); 258 ASSERT_INT_EQ(kex_send_kexinit(server), 0);
212 run_kex(client, server, s2c, c2s, direction, packet_index, 259 run_kex(client, server);
213 dump_path, replace_data);
214 TEST_DONE(); 260 TEST_DONE();
215 261
216 TEST_START("ssh_packet_get_state"); 262 TEST_START("ssh_packet_get_state");
@@ -221,9 +267,6 @@ do_kex_with_key(const char *kex, struct sshkey *prvkey, int *c2s, int *s2c,
221 TEST_DONE(); 267 TEST_DONE();
222 268
223 TEST_START("ssh_packet_set_state"); 269 TEST_START("ssh_packet_set_state");
224 server2 = NULL;
225 ASSERT_INT_EQ(ssh_init(&server2, 1, NULL), 0);
226 ASSERT_PTR_NE(server2, NULL);
227 ASSERT_INT_EQ(ssh_add_hostkey(server2, prvkey), 0); 270 ASSERT_INT_EQ(ssh_add_hostkey(server2, prvkey), 0);
228 kex_free(server2->kex); /* XXX or should ssh_packet_set_state()? */ 271 kex_free(server2->kex); /* XXX or should ssh_packet_set_state()? */
229 ASSERT_INT_EQ(ssh_packet_set_state(server2, state), 0); 272 ASSERT_INT_EQ(ssh_packet_set_state(server2, state), 0);
@@ -251,11 +294,9 @@ do_kex_with_key(const char *kex, struct sshkey *prvkey, int *c2s, int *s2c,
251 294
252 TEST_START("rekeying server2"); 295 TEST_START("rekeying server2");
253 ASSERT_INT_EQ(kex_send_kexinit(server2), 0); 296 ASSERT_INT_EQ(kex_send_kexinit(server2), 0);
254 run_kex(client, server2, s2c, c2s, direction, packet_index, 297 run_kex(client, server2);
255 dump_path, replace_data);
256 ASSERT_INT_EQ(kex_send_kexinit(client), 0); 298 ASSERT_INT_EQ(kex_send_kexinit(client), 0);
257 run_kex(client, server2, s2c, c2s, direction, packet_index, 299 run_kex(client, server2);
258 dump_path, replace_data);
259 TEST_DONE(); 300 TEST_DONE();
260 301
261 TEST_START("cleanup"); 302 TEST_START("cleanup");
@@ -357,6 +398,9 @@ main(int argc, char **argv)
357 argc -= optind; 398 argc -= optind;
358 argv += optind; 399 argv += optind;
359 400
401 log_init(argv[0], do_debug ? SYSLOG_LEVEL_DEBUG3 : SYSLOG_LEVEL_INFO,
402 SYSLOG_FACILITY_USER, 1);
403
360 /* Must select a single mode */ 404 /* Must select a single mode */
361 if ((count_flag + dump_flag + replace_flag) != 1) 405 if ((count_flag + dump_flag + replace_flag) != 1)
362 badusage("Must select one mode: -c, -d or -r"); 406 badusage("Must select one mode: -c, -d or -r");