1/* 	$OpenBSD: test_fuzz.c,v 1.8 2017/12/21 00:41:22 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
39void sshkey_fuzz_tests(void);
40
41static void
42onerror(void *fuzz)
43{
44	fprintf(stderr, "Failed during fuzz:\n");
45	fuzz_dump((struct fuzz *)fuzz);
46}
47
48static void
49public_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
74static void
75sig_fuzz(struct sshkey *k, const char *sig_alg)
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), sig_alg, 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), NULL, 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), NULL, 0), 0);
95	}
96	fuzz_cleanup(fuzz);
97}
98
99void
100sshkey_fuzz_tests(void)
101{
102	struct sshkey *k1;
103	struct sshbuf *buf, *fuzzed;
104	struct fuzz *fuzz;
105	int r;
106
107
108	TEST_START("fuzz RSA private");
109	buf = load_file("rsa_1");
110	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
111	    sshbuf_len(buf));
112	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
113	sshkey_free(k1);
114	sshbuf_free(buf);
115	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
116	TEST_ONERROR(onerror, fuzz);
117	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
118		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
119		ASSERT_INT_EQ(r, 0);
120		if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0)
121			sshkey_free(k1);
122		sshbuf_reset(fuzzed);
123	}
124	sshbuf_free(fuzzed);
125	fuzz_cleanup(fuzz);
126	TEST_DONE();
127
128	TEST_START("fuzz RSA new-format private");
129	buf = load_file("rsa_n");
130	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
131	    sshbuf_len(buf));
132	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
133	sshkey_free(k1);
134	sshbuf_free(buf);
135	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
136	TEST_ONERROR(onerror, fuzz);
137	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
138		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
139		ASSERT_INT_EQ(r, 0);
140		if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0)
141			sshkey_free(k1);
142		sshbuf_reset(fuzzed);
143	}
144	sshbuf_free(fuzzed);
145	fuzz_cleanup(fuzz);
146	TEST_DONE();
147
148	TEST_START("fuzz DSA private");
149	buf = load_file("dsa_1");
150	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
151	    sshbuf_len(buf));
152	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
153	sshkey_free(k1);
154	sshbuf_free(buf);
155	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
156	TEST_ONERROR(onerror, fuzz);
157	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
158		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
159		ASSERT_INT_EQ(r, 0);
160		if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0)
161			sshkey_free(k1);
162		sshbuf_reset(fuzzed);
163	}
164	sshbuf_free(fuzzed);
165	fuzz_cleanup(fuzz);
166	TEST_DONE();
167
168	TEST_START("fuzz DSA new-format private");
169	buf = load_file("dsa_n");
170	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
171	    sshbuf_len(buf));
172	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
173	sshkey_free(k1);
174	sshbuf_free(buf);
175	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
176	TEST_ONERROR(onerror, fuzz);
177	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
178		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
179		ASSERT_INT_EQ(r, 0);
180		if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0)
181			sshkey_free(k1);
182		sshbuf_reset(fuzzed);
183	}
184	sshbuf_free(fuzzed);
185	fuzz_cleanup(fuzz);
186	TEST_DONE();
187
188#ifdef OPENSSL_HAS_ECC
189	TEST_START("fuzz ECDSA private");
190	buf = load_file("ecdsa_1");
191	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
192	    sshbuf_len(buf));
193	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
194	sshkey_free(k1);
195	sshbuf_free(buf);
196	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
197	TEST_ONERROR(onerror, fuzz);
198	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
199		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
200		ASSERT_INT_EQ(r, 0);
201		if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0)
202			sshkey_free(k1);
203		sshbuf_reset(fuzzed);
204	}
205	sshbuf_free(fuzzed);
206	fuzz_cleanup(fuzz);
207	TEST_DONE();
208
209	TEST_START("fuzz ECDSA new-format private");
210	buf = load_file("ecdsa_n");
211	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
212	    sshbuf_len(buf));
213	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
214	sshkey_free(k1);
215	sshbuf_free(buf);
216	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
217	TEST_ONERROR(onerror, fuzz);
218	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
219		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
220		ASSERT_INT_EQ(r, 0);
221		if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0)
222			sshkey_free(k1);
223		sshbuf_reset(fuzzed);
224	}
225	sshbuf_free(fuzzed);
226	fuzz_cleanup(fuzz);
227	TEST_DONE();
228#endif
229
230	TEST_START("fuzz Ed25519 private");
231	buf = load_file("ed25519_1");
232	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
233	    sshbuf_len(buf));
234	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
235	sshkey_free(k1);
236	sshbuf_free(buf);
237	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
238	TEST_ONERROR(onerror, fuzz);
239	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
240		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
241		ASSERT_INT_EQ(r, 0);
242		if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0)
243			sshkey_free(k1);
244		sshbuf_reset(fuzzed);
245	}
246	sshbuf_free(fuzzed);
247	fuzz_cleanup(fuzz);
248	TEST_DONE();
249
250	TEST_START("fuzz RSA public");
251	buf = load_file("rsa_1");
252	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
253	sshbuf_free(buf);
254	public_fuzz(k1);
255	sshkey_free(k1);
256	TEST_DONE();
257
258	TEST_START("fuzz RSA cert");
259	ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1"), &k1), 0);
260	public_fuzz(k1);
261	sshkey_free(k1);
262	TEST_DONE();
263
264	TEST_START("fuzz DSA public");
265	buf = load_file("dsa_1");
266	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
267	sshbuf_free(buf);
268	public_fuzz(k1);
269	sshkey_free(k1);
270	TEST_DONE();
271
272	TEST_START("fuzz DSA cert");
273	ASSERT_INT_EQ(sshkey_load_cert(test_data_file("dsa_1"), &k1), 0);
274	public_fuzz(k1);
275	sshkey_free(k1);
276	TEST_DONE();
277
278#ifdef OPENSSL_HAS_ECC
279	TEST_START("fuzz ECDSA public");
280	buf = load_file("ecdsa_1");
281	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
282	sshbuf_free(buf);
283	public_fuzz(k1);
284	sshkey_free(k1);
285	TEST_DONE();
286
287	TEST_START("fuzz ECDSA cert");
288	ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ecdsa_1"), &k1), 0);
289	public_fuzz(k1);
290	sshkey_free(k1);
291	TEST_DONE();
292#endif
293
294	TEST_START("fuzz Ed25519 public");
295	buf = load_file("ed25519_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 Ed25519 cert");
303	ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ed25519_1"), &k1), 0);
304	public_fuzz(k1);
305	sshkey_free(k1);
306	TEST_DONE();
307
308	TEST_START("fuzz RSA sig");
309	buf = load_file("rsa_1");
310	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
311	sshbuf_free(buf);
312	sig_fuzz(k1, "ssh-rsa");
313	sshkey_free(k1);
314	TEST_DONE();
315
316	TEST_START("fuzz RSA SHA256 sig");
317	buf = load_file("rsa_1");
318	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
319	sshbuf_free(buf);
320	sig_fuzz(k1, "rsa-sha2-256");
321	sshkey_free(k1);
322	TEST_DONE();
323
324	TEST_START("fuzz RSA SHA512 sig");
325	buf = load_file("rsa_1");
326	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
327	sshbuf_free(buf);
328	sig_fuzz(k1, "rsa-sha2-512");
329	sshkey_free(k1);
330	TEST_DONE();
331
332	TEST_START("fuzz DSA sig");
333	buf = load_file("dsa_1");
334	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
335	sshbuf_free(buf);
336	sig_fuzz(k1, NULL);
337	sshkey_free(k1);
338	TEST_DONE();
339
340#ifdef OPENSSL_HAS_ECC
341	TEST_START("fuzz ECDSA sig");
342	buf = load_file("ecdsa_1");
343	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
344	sshbuf_free(buf);
345	sig_fuzz(k1, NULL);
346	sshkey_free(k1);
347	TEST_DONE();
348#endif
349
350	TEST_START("fuzz Ed25519 sig");
351	buf = load_file("ed25519_1");
352	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
353	sshbuf_free(buf);
354	sig_fuzz(k1, NULL);
355	sshkey_free(k1);
356	TEST_DONE();
357
358/* XXX fuzz decoded new-format blobs too */
359
360}
361