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