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 *
unpack(const uint8_t * ptr,size_t len)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
pack(uint8_t * ptr,size_t len,const struct param * p)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
pack_dummy(uint8_t * ptr,size_t len)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
dev_reset(const struct param * p)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
dev_get_cbor_info(const struct param * p)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
dev_set_pin(const struct param * p)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
dev_change_pin(const struct param * p)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
dev_get_retry_count(const struct param * p)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
dev_get_uv_retry_count(const struct param * p)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
dev_enable_entattest(const struct param * p)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
dev_toggle_always_uv(const struct param * p)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
dev_force_pin_change(const struct param * p)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
dev_set_pin_minlen(const struct param * p)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
dev_set_pin_minlen_rpid(const struct param * p)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
test(const struct param * p)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
mutate(struct param * p,unsigned int seed,unsigned int flags)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