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