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