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