1 /* 	$OpenBSD: test_fuzz.c,v 1.4 2015/03/04 23:22:35 djm Exp $ */
2 /*
3  * Fuzz tests for key parsing
4  *
5  * Placed in the public domain
6  */
7 
8 #include "includes.h"
9 
10 #include <sys/types.h>
11 #include <sys/param.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <stdio.h>
15 #ifdef HAVE_STDINT_H
16 #include <stdint.h>
17 #endif
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 
22 #include <openssl/bn.h>
23 #include <openssl/rsa.h>
24 #include <openssl/dsa.h>
25 #include <openssl/objects.h>
26 #ifdef OPENSSL_HAS_NISTP256
27 # include <openssl/ec.h>
28 #endif
29 
30 #include "../test_helper/test_helper.h"
31 
32 #include "ssherr.h"
33 #include "authfile.h"
34 #include "sshkey.h"
35 #include "sshbuf.h"
36 
37 #include "common.h"
38 
39 void sshkey_fuzz_tests(void);
40 
41 static void
42 onerror(void *fuzz)
43 {
44 	fprintf(stderr, "Failed during fuzz:\n");
45 	fuzz_dump((struct fuzz *)fuzz);
46 }
47 
48 static void
49 public_fuzz(struct sshkey *k)
50 {
51 	struct sshkey *k1;
52 	struct sshbuf *buf;
53 	struct fuzz *fuzz;
54 
55 	ASSERT_PTR_NE(buf = sshbuf_new(), NULL);
56 	ASSERT_INT_EQ(sshkey_putb(k, buf), 0);
57 	/* XXX need a way to run the tests in "slow, but complete" mode */
58 	fuzz = fuzz_begin(FUZZ_1_BIT_FLIP | /* XXX too slow FUZZ_2_BIT_FLIP | */
59 	    FUZZ_1_BYTE_FLIP | /* XXX too slow FUZZ_2_BYTE_FLIP | */
60 	    FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END,
61 	    sshbuf_mutable_ptr(buf), sshbuf_len(buf));
62 	ASSERT_INT_EQ(sshkey_from_blob(sshbuf_ptr(buf), sshbuf_len(buf),
63 	    &k1), 0);
64 	sshkey_free(k1);
65 	sshbuf_free(buf);
66 	TEST_ONERROR(onerror, fuzz);
67 	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
68 		if (sshkey_from_blob(fuzz_ptr(fuzz), fuzz_len(fuzz), &k1) == 0)
69 			sshkey_free(k1);
70 	}
71 	fuzz_cleanup(fuzz);
72 }
73 
74 static void
75 sig_fuzz(struct sshkey *k)
76 {
77 	struct fuzz *fuzz;
78 	u_char *sig, c[] = "some junk to be signed";
79 	size_t l;
80 
81 	ASSERT_INT_EQ(sshkey_sign(k, &sig, &l, c, sizeof(c), 0), 0);
82 	ASSERT_SIZE_T_GT(l, 0);
83 	fuzz = fuzz_begin(FUZZ_1_BIT_FLIP | /* too slow FUZZ_2_BIT_FLIP | */
84 	    FUZZ_1_BYTE_FLIP | FUZZ_2_BYTE_FLIP |
85 	    FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END, sig, l);
86 	ASSERT_INT_EQ(sshkey_verify(k, sig, l, c, sizeof(c), 0), 0);
87 	free(sig);
88 	TEST_ONERROR(onerror, fuzz);
89 	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
90 		/* Ensure 1-bit difference at least */
91 		if (fuzz_matches_original(fuzz))
92 			continue;
93 		ASSERT_INT_NE(sshkey_verify(k, fuzz_ptr(fuzz), fuzz_len(fuzz),
94 		    c, sizeof(c), 0), 0);
95 	}
96 	fuzz_cleanup(fuzz);
97 }
98 
99 void
100 sshkey_fuzz_tests(void)
101 {
102 	struct sshkey *k1;
103 	struct sshbuf *buf, *fuzzed;
104 	struct fuzz *fuzz;
105 	int r;
106 
107 #ifdef WITH_SSH1
108 	TEST_START("fuzz RSA1 private");
109 	buf = load_file("rsa1_1");
110 	fuzz = fuzz_begin(FUZZ_1_BIT_FLIP | FUZZ_1_BYTE_FLIP |
111 	    FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END,
112 	    sshbuf_mutable_ptr(buf), sshbuf_len(buf));
113 	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
114 	    &k1, NULL), 0);
115 	sshkey_free(k1);
116 	sshbuf_free(buf);
117 	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
118 	TEST_ONERROR(onerror, fuzz);
119 	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
120 		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
121 		ASSERT_INT_EQ(r, 0);
122 		if (sshkey_parse_private_fileblob(fuzzed, "", "key",
123 		    &k1, NULL) == 0)
124 			sshkey_free(k1);
125 		sshbuf_reset(fuzzed);
126 	}
127 	sshbuf_free(fuzzed);
128 	fuzz_cleanup(fuzz);
129 	TEST_DONE();
130 
131 	TEST_START("fuzz RSA1 public");
132 	buf = load_file("rsa1_1_pw");
133 	fuzz = fuzz_begin(FUZZ_1_BIT_FLIP | FUZZ_1_BYTE_FLIP |
134 	    FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END,
135 	    sshbuf_mutable_ptr(buf), sshbuf_len(buf));
136 	ASSERT_INT_EQ(sshkey_parse_public_rsa1_fileblob(buf, &k1, NULL), 0);
137 	sshkey_free(k1);
138 	sshbuf_free(buf);
139 	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
140 	TEST_ONERROR(onerror, fuzz);
141 	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
142 		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
143 		ASSERT_INT_EQ(r, 0);
144 		if (sshkey_parse_public_rsa1_fileblob(fuzzed, &k1, NULL) == 0)
145 			sshkey_free(k1);
146 		sshbuf_reset(fuzzed);
147 	}
148 	sshbuf_free(fuzzed);
149 	fuzz_cleanup(fuzz);
150 	TEST_DONE();
151 #endif
152 
153 	TEST_START("fuzz RSA private");
154 	buf = load_file("rsa_1");
155 	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
156 	    sshbuf_len(buf));
157 	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
158 	    &k1, NULL), 0);
159 	sshkey_free(k1);
160 	sshbuf_free(buf);
161 	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
162 	TEST_ONERROR(onerror, fuzz);
163 	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
164 		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
165 		ASSERT_INT_EQ(r, 0);
166 		if (sshkey_parse_private_fileblob(fuzzed, "", "key",
167 		    &k1, NULL) == 0)
168 			sshkey_free(k1);
169 		sshbuf_reset(fuzzed);
170 	}
171 	sshbuf_free(fuzzed);
172 	fuzz_cleanup(fuzz);
173 	TEST_DONE();
174 
175 	TEST_START("fuzz RSA new-format private");
176 	buf = load_file("rsa_n");
177 	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
178 	    sshbuf_len(buf));
179 	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
180 	    &k1, NULL), 0);
181 	sshkey_free(k1);
182 	sshbuf_free(buf);
183 	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
184 	TEST_ONERROR(onerror, fuzz);
185 	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
186 		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
187 		ASSERT_INT_EQ(r, 0);
188 		if (sshkey_parse_private_fileblob(fuzzed, "", "key",
189 		    &k1, NULL) == 0)
190 			sshkey_free(k1);
191 		sshbuf_reset(fuzzed);
192 	}
193 	sshbuf_free(fuzzed);
194 	fuzz_cleanup(fuzz);
195 	TEST_DONE();
196 
197 	TEST_START("fuzz DSA private");
198 	buf = load_file("dsa_1");
199 	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
200 	    sshbuf_len(buf));
201 	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
202 	    &k1, NULL), 0);
203 	sshkey_free(k1);
204 	sshbuf_free(buf);
205 	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
206 	TEST_ONERROR(onerror, fuzz);
207 	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
208 		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
209 		ASSERT_INT_EQ(r, 0);
210 		if (sshkey_parse_private_fileblob(fuzzed, "", "key",
211 		    &k1, NULL) == 0)
212 			sshkey_free(k1);
213 		sshbuf_reset(fuzzed);
214 	}
215 	sshbuf_free(fuzzed);
216 	fuzz_cleanup(fuzz);
217 	TEST_DONE();
218 
219 	TEST_START("fuzz DSA new-format private");
220 	buf = load_file("dsa_n");
221 	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
222 	    sshbuf_len(buf));
223 	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
224 	    &k1, NULL), 0);
225 	sshkey_free(k1);
226 	sshbuf_free(buf);
227 	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
228 	TEST_ONERROR(onerror, fuzz);
229 	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
230 		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
231 		ASSERT_INT_EQ(r, 0);
232 		if (sshkey_parse_private_fileblob(fuzzed, "", "key",
233 		    &k1, NULL) == 0)
234 			sshkey_free(k1);
235 		sshbuf_reset(fuzzed);
236 	}
237 	sshbuf_free(fuzzed);
238 	fuzz_cleanup(fuzz);
239 	TEST_DONE();
240 
241 #ifdef OPENSSL_HAS_ECC
242 	TEST_START("fuzz ECDSA private");
243 	buf = load_file("ecdsa_1");
244 	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
245 	    sshbuf_len(buf));
246 	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
247 	    &k1, NULL), 0);
248 	sshkey_free(k1);
249 	sshbuf_free(buf);
250 	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
251 	TEST_ONERROR(onerror, fuzz);
252 	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
253 		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
254 		ASSERT_INT_EQ(r, 0);
255 		if (sshkey_parse_private_fileblob(fuzzed, "", "key",
256 		    &k1, NULL) == 0)
257 			sshkey_free(k1);
258 		sshbuf_reset(fuzzed);
259 	}
260 	sshbuf_free(fuzzed);
261 	fuzz_cleanup(fuzz);
262 	TEST_DONE();
263 
264 	TEST_START("fuzz ECDSA new-format private");
265 	buf = load_file("ecdsa_n");
266 	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
267 	    sshbuf_len(buf));
268 	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
269 	    &k1, NULL), 0);
270 	sshkey_free(k1);
271 	sshbuf_free(buf);
272 	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
273 	TEST_ONERROR(onerror, fuzz);
274 	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
275 		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
276 		ASSERT_INT_EQ(r, 0);
277 		if (sshkey_parse_private_fileblob(fuzzed, "", "key",
278 		    &k1, NULL) == 0)
279 			sshkey_free(k1);
280 		sshbuf_reset(fuzzed);
281 	}
282 	sshbuf_free(fuzzed);
283 	fuzz_cleanup(fuzz);
284 	TEST_DONE();
285 #endif
286 
287 	TEST_START("fuzz Ed25519 private");
288 	buf = load_file("ed25519_1");
289 	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
290 	    sshbuf_len(buf));
291 	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
292 	    &k1, NULL), 0);
293 	sshkey_free(k1);
294 	sshbuf_free(buf);
295 	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
296 	TEST_ONERROR(onerror, fuzz);
297 	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
298 		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
299 		ASSERT_INT_EQ(r, 0);
300 		if (sshkey_parse_private_fileblob(fuzzed, "", "key",
301 		    &k1, NULL) == 0)
302 			sshkey_free(k1);
303 		sshbuf_reset(fuzzed);
304 	}
305 	sshbuf_free(fuzzed);
306 	fuzz_cleanup(fuzz);
307 	TEST_DONE();
308 
309 	TEST_START("fuzz RSA public");
310 	buf = load_file("rsa_1");
311 	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
312 	    &k1, NULL), 0);
313 	sshbuf_free(buf);
314 	public_fuzz(k1);
315 	sshkey_free(k1);
316 	TEST_DONE();
317 
318 	TEST_START("fuzz RSA cert");
319 	ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1"), &k1), 0);
320 	public_fuzz(k1);
321 	sshkey_free(k1);
322 	TEST_DONE();
323 
324 	TEST_START("fuzz DSA public");
325 	buf = load_file("dsa_1");
326 	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
327 	    &k1, NULL), 0);
328 	sshbuf_free(buf);
329 	public_fuzz(k1);
330 	sshkey_free(k1);
331 	TEST_DONE();
332 
333 	TEST_START("fuzz DSA cert");
334 	ASSERT_INT_EQ(sshkey_load_cert(test_data_file("dsa_1"), &k1), 0);
335 	public_fuzz(k1);
336 	sshkey_free(k1);
337 	TEST_DONE();
338 
339 #ifdef OPENSSL_HAS_ECC
340 	TEST_START("fuzz ECDSA public");
341 	buf = load_file("ecdsa_1");
342 	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
343 	    &k1, NULL), 0);
344 	sshbuf_free(buf);
345 	public_fuzz(k1);
346 	sshkey_free(k1);
347 	TEST_DONE();
348 
349 	TEST_START("fuzz ECDSA cert");
350 	ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ecdsa_1"), &k1), 0);
351 	public_fuzz(k1);
352 	sshkey_free(k1);
353 	TEST_DONE();
354 #endif
355 
356 	TEST_START("fuzz Ed25519 public");
357 	buf = load_file("ed25519_1");
358 	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
359 	    &k1, NULL), 0);
360 	sshbuf_free(buf);
361 	public_fuzz(k1);
362 	sshkey_free(k1);
363 	TEST_DONE();
364 
365 	TEST_START("fuzz Ed25519 cert");
366 	ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ed25519_1"), &k1), 0);
367 	public_fuzz(k1);
368 	sshkey_free(k1);
369 	TEST_DONE();
370 
371 	TEST_START("fuzz RSA sig");
372 	buf = load_file("rsa_1");
373 	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
374 	    &k1, NULL), 0);
375 	sshbuf_free(buf);
376 	sig_fuzz(k1);
377 	sshkey_free(k1);
378 	TEST_DONE();
379 
380 	TEST_START("fuzz DSA sig");
381 	buf = load_file("dsa_1");
382 	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
383 	    &k1, NULL), 0);
384 	sshbuf_free(buf);
385 	sig_fuzz(k1);
386 	sshkey_free(k1);
387 	TEST_DONE();
388 
389 #ifdef OPENSSL_HAS_ECC
390 	TEST_START("fuzz ECDSA sig");
391 	buf = load_file("ecdsa_1");
392 	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
393 	    &k1, NULL), 0);
394 	sshbuf_free(buf);
395 	sig_fuzz(k1);
396 	sshkey_free(k1);
397 	TEST_DONE();
398 #endif
399 
400 	TEST_START("fuzz Ed25519 sig");
401 	buf = load_file("ed25519_1");
402 	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
403 	    &k1, NULL), 0);
404 	sshbuf_free(buf);
405 	sig_fuzz(k1);
406 	sshkey_free(k1);
407 	TEST_DONE();
408 
409 /* XXX fuzz decoded new-format blobs too */
410 
411 }
412