xref: /freebsd/contrib/libfido2/fuzz/fuzz_mgmt.c (revision ba3c1f5972d7b90feb6e6da47905ff2757e0fe57)
1 /*
2  * Copyright (c) 2019 Yubico AB. All rights reserved.
3  * Use of this source code is governed by a BSD-style
4  * license that can be found in the LICENSE file.
5  */
6 
7 #include <assert.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 #include "mutator_aux.h"
14 #include "wiredata_fido2.h"
15 #include "dummy.h"
16 
17 #include "../openbsd-compat/openbsd-compat.h"
18 
19 #define MAXRPID	64
20 
21 struct param {
22 	char pin1[MAXSTR];
23 	char pin2[MAXSTR];
24 	struct blob reset_wire_data;
25 	struct blob info_wire_data;
26 	struct blob set_pin_wire_data;
27 	struct blob change_pin_wire_data;
28 	struct blob retry_wire_data;
29 	struct blob config_wire_data;
30 	int seed;
31 };
32 
33 static const uint8_t dummy_reset_wire_data[] = {
34 	WIREDATA_CTAP_INIT,
35 	WIREDATA_CTAP_CBOR_INFO,
36 	WIREDATA_CTAP_KEEPALIVE,
37 	WIREDATA_CTAP_KEEPALIVE,
38 	WIREDATA_CTAP_KEEPALIVE,
39 	WIREDATA_CTAP_CBOR_STATUS,
40 };
41 
42 static const uint8_t dummy_info_wire_data[] = {
43 	WIREDATA_CTAP_INIT,
44 	WIREDATA_CTAP_CBOR_INFO,
45 	WIREDATA_CTAP_CBOR_INFO,
46 };
47 
48 static const uint8_t dummy_set_pin_wire_data[] = {
49 	WIREDATA_CTAP_INIT,
50 	WIREDATA_CTAP_CBOR_INFO,
51 	WIREDATA_CTAP_CBOR_AUTHKEY,
52 	WIREDATA_CTAP_CBOR_STATUS,
53 };
54 
55 static const uint8_t dummy_change_pin_wire_data[] = {
56 	WIREDATA_CTAP_INIT,
57 	WIREDATA_CTAP_CBOR_INFO,
58 	WIREDATA_CTAP_CBOR_AUTHKEY,
59 	WIREDATA_CTAP_CBOR_STATUS,
60 };
61 
62 static const uint8_t dummy_retry_wire_data[] = {
63 	WIREDATA_CTAP_INIT,
64 	WIREDATA_CTAP_CBOR_INFO,
65 	WIREDATA_CTAP_CBOR_RETRIES,
66 };
67 
68 static const uint8_t dummy_config_wire_data[] = {
69 	WIREDATA_CTAP_INIT,
70 	WIREDATA_CTAP_CBOR_INFO,
71 	WIREDATA_CTAP_CBOR_STATUS,
72 };
73 
74 struct param *
75 unpack(const uint8_t *ptr, size_t len)
76 {
77 	cbor_item_t *item = NULL, **v;
78 	struct cbor_load_result cbor;
79 	struct param *p;
80 	int ok = -1;
81 
82 	if ((p = calloc(1, sizeof(*p))) == NULL ||
83 	    (item = cbor_load(ptr, len, &cbor)) == NULL ||
84 	    cbor.read != len ||
85 	    cbor_isa_array(item) == false ||
86 	    cbor_array_is_definite(item) == false ||
87 	    cbor_array_size(item) != 9 ||
88 	    (v = cbor_array_handle(item)) == NULL)
89 		goto fail;
90 
91 	if (unpack_int(v[0], &p->seed) < 0 ||
92 	    unpack_string(v[1], p->pin1) < 0 ||
93 	    unpack_string(v[2], p->pin2) < 0 ||
94 	    unpack_blob(v[3], &p->reset_wire_data) < 0 ||
95 	    unpack_blob(v[4], &p->info_wire_data) < 0 ||
96 	    unpack_blob(v[5], &p->set_pin_wire_data) < 0 ||
97 	    unpack_blob(v[6], &p->change_pin_wire_data) < 0 ||
98 	    unpack_blob(v[7], &p->retry_wire_data) < 0 ||
99 	    unpack_blob(v[8], &p->config_wire_data) < 0)
100 		goto fail;
101 
102 	ok = 0;
103 fail:
104 	if (ok < 0) {
105 		free(p);
106 		p = NULL;
107 	}
108 
109 	if (item)
110 		cbor_decref(&item);
111 
112 	return p;
113 }
114 
115 size_t
116 pack(uint8_t *ptr, size_t len, const struct param *p)
117 {
118 	cbor_item_t *argv[9], *array = NULL;
119 	size_t cbor_alloc_len, cbor_len = 0;
120 	unsigned char *cbor = NULL;
121 
122 	memset(argv, 0, sizeof(argv));
123 
124 	if ((array = cbor_new_definite_array(9)) == NULL ||
125 	    (argv[0] = pack_int(p->seed)) == NULL ||
126 	    (argv[1] = pack_string(p->pin1)) == NULL ||
127 	    (argv[2] = pack_string(p->pin2)) == NULL ||
128 	    (argv[3] = pack_blob(&p->reset_wire_data)) == NULL ||
129 	    (argv[4] = pack_blob(&p->info_wire_data)) == NULL ||
130 	    (argv[5] = pack_blob(&p->set_pin_wire_data)) == NULL ||
131 	    (argv[6] = pack_blob(&p->change_pin_wire_data)) == NULL ||
132 	    (argv[7] = pack_blob(&p->retry_wire_data)) == NULL ||
133 	    (argv[8] = pack_blob(&p->config_wire_data)) == NULL)
134 		goto fail;
135 
136 	for (size_t i = 0; i < 9; i++)
137 		if (cbor_array_push(array, argv[i]) == false)
138 			goto fail;
139 
140 	if ((cbor_len = cbor_serialize_alloc(array, &cbor,
141 	    &cbor_alloc_len)) > len) {
142 		cbor_len = 0;
143 		goto fail;
144 	}
145 
146 	memcpy(ptr, cbor, cbor_len);
147 fail:
148 	for (size_t i = 0; i < 9; i++)
149 		if (argv[i])
150 			cbor_decref(&argv[i]);
151 
152 	if (array)
153 		cbor_decref(&array);
154 
155 	free(cbor);
156 
157 	return cbor_len;
158 }
159 
160 size_t
161 pack_dummy(uint8_t *ptr, size_t len)
162 {
163 	struct param dummy;
164 	uint8_t blob[4096];
165 	size_t blob_len;
166 
167 	memset(&dummy, 0, sizeof(dummy));
168 
169 	strlcpy(dummy.pin1, dummy_pin1, sizeof(dummy.pin1));
170 	strlcpy(dummy.pin2, dummy_pin2, sizeof(dummy.pin2));
171 
172 	dummy.reset_wire_data.len = sizeof(dummy_reset_wire_data);
173 	dummy.info_wire_data.len = sizeof(dummy_info_wire_data);
174 	dummy.set_pin_wire_data.len = sizeof(dummy_set_pin_wire_data);
175 	dummy.change_pin_wire_data.len = sizeof(dummy_change_pin_wire_data);
176 	dummy.retry_wire_data.len = sizeof(dummy_retry_wire_data);
177 	dummy.config_wire_data.len = sizeof(dummy_config_wire_data);
178 
179 	memcpy(&dummy.reset_wire_data.body, &dummy_reset_wire_data,
180 	    dummy.reset_wire_data.len);
181 	memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data,
182 	    dummy.info_wire_data.len);
183 	memcpy(&dummy.set_pin_wire_data.body, &dummy_set_pin_wire_data,
184 	    dummy.set_pin_wire_data.len);
185 	memcpy(&dummy.change_pin_wire_data.body, &dummy_change_pin_wire_data,
186 	    dummy.change_pin_wire_data.len);
187 	memcpy(&dummy.retry_wire_data.body, &dummy_retry_wire_data,
188 	    dummy.retry_wire_data.len);
189 	memcpy(&dummy.config_wire_data.body, &dummy_config_wire_data,
190 	    dummy.config_wire_data.len);
191 
192 	assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
193 
194 	if (blob_len > len) {
195 		memcpy(ptr, blob, len);
196 		return len;
197 	}
198 
199 	memcpy(ptr, blob, blob_len);
200 
201 	return blob_len;
202 }
203 
204 static void
205 dev_reset(const struct param *p)
206 {
207 	fido_dev_t *dev;
208 
209 	set_wire_data(p->reset_wire_data.body, p->reset_wire_data.len);
210 
211 	if ((dev = open_dev(0)) == NULL)
212 		return;
213 
214 	fido_dev_reset(dev);
215 	fido_dev_close(dev);
216 	fido_dev_free(&dev);
217 }
218 
219 static void
220 dev_get_cbor_info(const struct param *p)
221 {
222 	fido_dev_t *dev;
223 	fido_cbor_info_t *ci;
224 	uint64_t n;
225 	uint8_t proto, major, minor, build, flags;
226 
227 	set_wire_data(p->info_wire_data.body, p->info_wire_data.len);
228 
229 	if ((dev = open_dev(0)) == NULL)
230 		return;
231 
232 	proto = fido_dev_protocol(dev);
233 	major = fido_dev_major(dev);
234 	minor = fido_dev_minor(dev);
235 	build = fido_dev_build(dev);
236 	flags = fido_dev_flags(dev);
237 
238 	consume(&proto, sizeof(proto));
239 	consume(&major, sizeof(major));
240 	consume(&minor, sizeof(minor));
241 	consume(&build, sizeof(build));
242 	consume(&flags, sizeof(flags));
243 
244 	if ((ci = fido_cbor_info_new()) == NULL)
245 		goto out;
246 
247 	fido_dev_get_cbor_info(dev, ci);
248 
249 	for (size_t i = 0; i < fido_cbor_info_versions_len(ci); i++) {
250 		char * const *sa = fido_cbor_info_versions_ptr(ci);
251 		consume(sa[i], strlen(sa[i]));
252 	}
253 
254 	for (size_t i = 0; i < fido_cbor_info_extensions_len(ci); i++) {
255 		char * const *sa = fido_cbor_info_extensions_ptr(ci);
256 		consume(sa[i], strlen(sa[i]));
257 	}
258 
259 	for (size_t i = 0; i < fido_cbor_info_transports_len(ci); i++) {
260 		char * const *sa = fido_cbor_info_transports_ptr(ci);
261 		consume(sa[i], strlen(sa[i]));
262 	}
263 
264 	for (size_t i = 0; i < fido_cbor_info_options_len(ci); i++) {
265 		char * const *sa = fido_cbor_info_options_name_ptr(ci);
266 		const bool *va = fido_cbor_info_options_value_ptr(ci);
267 		consume(sa[i], strlen(sa[i]));
268 		consume(&va[i], sizeof(va[i]));
269 	}
270 
271 	/* +1 on purpose */
272 	for (size_t i = 0; i <= fido_cbor_info_algorithm_count(ci); i++) {
273 		const char *type = fido_cbor_info_algorithm_type(ci, i);
274 		int cose = fido_cbor_info_algorithm_cose(ci, i);
275 		consume_str(type);
276 		consume(&cose, sizeof(cose));
277 	}
278 
279 	n = fido_cbor_info_maxmsgsiz(ci);
280 	consume(&n, sizeof(n));
281 
282 	n = fido_cbor_info_maxcredbloblen(ci);
283 	consume(&n, sizeof(n));
284 
285 	n = fido_cbor_info_maxcredcntlst(ci);
286 	consume(&n, sizeof(n));
287 
288 	n = fido_cbor_info_maxcredidlen(ci);
289 	consume(&n, sizeof(n));
290 
291 	n = fido_cbor_info_fwversion(ci);
292 	consume(&n, sizeof(n));
293 
294 	consume(fido_cbor_info_aaguid_ptr(ci), fido_cbor_info_aaguid_len(ci));
295 	consume(fido_cbor_info_protocols_ptr(ci),
296 	    fido_cbor_info_protocols_len(ci));
297 
298 out:
299 	fido_dev_close(dev);
300 	fido_dev_free(&dev);
301 
302 	fido_cbor_info_free(&ci);
303 }
304 
305 static void
306 dev_set_pin(const struct param *p)
307 {
308 	fido_dev_t *dev;
309 
310 	set_wire_data(p->set_pin_wire_data.body, p->set_pin_wire_data.len);
311 
312 	if ((dev = open_dev(0)) == NULL)
313 		return;
314 
315 	fido_dev_set_pin(dev, p->pin1, NULL);
316 	fido_dev_close(dev);
317 	fido_dev_free(&dev);
318 }
319 
320 static void
321 dev_change_pin(const struct param *p)
322 {
323 	fido_dev_t *dev;
324 
325 	set_wire_data(p->change_pin_wire_data.body, p->change_pin_wire_data.len);
326 
327 	if ((dev = open_dev(0)) == NULL)
328 		return;
329 
330 	fido_dev_set_pin(dev, p->pin2, p->pin1);
331 	fido_dev_close(dev);
332 	fido_dev_free(&dev);
333 }
334 
335 static void
336 dev_get_retry_count(const struct param *p)
337 {
338 	fido_dev_t *dev;
339 	int n = 0;
340 
341 	set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len);
342 
343 	if ((dev = open_dev(0)) == NULL)
344 		return;
345 
346 	fido_dev_get_retry_count(dev, &n);
347 	consume(&n, sizeof(n));
348 	fido_dev_close(dev);
349 	fido_dev_free(&dev);
350 }
351 
352 static void
353 dev_get_uv_retry_count(const struct param *p)
354 {
355 	fido_dev_t *dev;
356 	int n = 0;
357 
358 	set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len);
359 
360 	if ((dev = open_dev(0)) == NULL)
361 		return;
362 
363 	fido_dev_get_uv_retry_count(dev, &n);
364 	consume(&n, sizeof(n));
365 	fido_dev_close(dev);
366 	fido_dev_free(&dev);
367 }
368 
369 static void
370 dev_enable_entattest(const struct param *p)
371 {
372 	fido_dev_t *dev;
373 	const char *pin;
374 	int r;
375 
376 	set_wire_data(p->config_wire_data.body, p->config_wire_data.len);
377 	if ((dev = open_dev(0)) == NULL)
378 		return;
379 	pin = p->pin1;
380 	if (strlen(pin) == 0)
381 		pin = NULL;
382 	r = fido_dev_enable_entattest(dev, pin);
383 	consume_str(fido_strerr(r));
384 	fido_dev_close(dev);
385 	fido_dev_free(&dev);
386 }
387 
388 static void
389 dev_toggle_always_uv(const struct param *p)
390 {
391 	fido_dev_t *dev;
392 	const char *pin;
393 	int r;
394 
395 	set_wire_data(p->config_wire_data.body, p->config_wire_data.len);
396 	if ((dev = open_dev(0)) == NULL)
397 		return;
398 	pin = p->pin1;
399 	if (strlen(pin) == 0)
400 		pin = NULL;
401 	r = fido_dev_toggle_always_uv(dev, pin);
402 	consume_str(fido_strerr(r));
403 	fido_dev_close(dev);
404 	fido_dev_free(&dev);
405 }
406 
407 static void
408 dev_force_pin_change(const struct param *p)
409 {
410 	fido_dev_t *dev;
411 	const char *pin;
412 	int r;
413 
414 	set_wire_data(p->config_wire_data.body, p->config_wire_data.len);
415 	if ((dev = open_dev(0)) == NULL)
416 		return;
417 	pin = p->pin1;
418 	if (strlen(pin) == 0)
419 		pin = NULL;
420 	r = fido_dev_force_pin_change(dev, pin);
421 	consume_str(fido_strerr(r));
422 	fido_dev_close(dev);
423 	fido_dev_free(&dev);
424 }
425 
426 static void
427 dev_set_pin_minlen(const struct param *p)
428 {
429 	fido_dev_t *dev;
430 	const char *pin;
431 	int r;
432 
433 	set_wire_data(p->config_wire_data.body, p->config_wire_data.len);
434 	if ((dev = open_dev(0)) == NULL)
435 		return;
436 	pin = p->pin1;
437 	if (strlen(pin) == 0)
438 		pin = NULL;
439 	r = fido_dev_set_pin_minlen(dev, strlen(p->pin2), pin);
440 	consume_str(fido_strerr(r));
441 	fido_dev_close(dev);
442 	fido_dev_free(&dev);
443 }
444 
445 static void
446 dev_set_pin_minlen_rpid(const struct param *p)
447 {
448 	fido_dev_t *dev;
449 	const char *rpid[MAXRPID];
450 	const char *pin;
451 	size_t n;
452 	int r;
453 
454 	set_wire_data(p->config_wire_data.body, p->config_wire_data.len);
455 	if ((dev = open_dev(0)) == NULL)
456 		return;
457 	n = uniform_random(MAXRPID);
458 	for (size_t i = 0; i < n; i++)
459 		rpid[i] = dummy_rp_id;
460 	pin = p->pin1;
461 	if (strlen(pin) == 0)
462 		pin = NULL;
463 	r = fido_dev_set_pin_minlen_rpid(dev, rpid, n, pin);
464 	consume_str(fido_strerr(r));
465 	fido_dev_close(dev);
466 	fido_dev_free(&dev);
467 }
468 
469 void
470 test(const struct param *p)
471 {
472 	prng_init((unsigned int)p->seed);
473 	fuzz_clock_reset();
474 	fido_init(FIDO_DEBUG);
475 	fido_set_log_handler(consume_str);
476 
477 	dev_reset(p);
478 	dev_get_cbor_info(p);
479 	dev_set_pin(p);
480 	dev_change_pin(p);
481 	dev_get_retry_count(p);
482 	dev_get_uv_retry_count(p);
483 	dev_enable_entattest(p);
484 	dev_toggle_always_uv(p);
485 	dev_force_pin_change(p);
486 	dev_set_pin_minlen(p);
487 	dev_set_pin_minlen_rpid(p);
488 }
489 
490 void
491 mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
492 {
493 	if (flags & MUTATE_SEED)
494 		p->seed = (int)seed;
495 
496 	if (flags & MUTATE_PARAM) {
497 		mutate_string(p->pin1);
498 		mutate_string(p->pin2);
499 	}
500 
501 	if (flags & MUTATE_WIREDATA) {
502 		mutate_blob(&p->reset_wire_data);
503 		mutate_blob(&p->info_wire_data);
504 		mutate_blob(&p->set_pin_wire_data);
505 		mutate_blob(&p->change_pin_wire_data);
506 		mutate_blob(&p->retry_wire_data);
507 	}
508 }
509