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