1 /*
2 * Copyright (c) 2019-2023 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 "wiredata_u2f.h"
17 #include "dummy.h"
18
19 #include "../openbsd-compat/openbsd-compat.h"
20
21 /* Parameter set defining a FIDO2 get assertion operation. */
22 struct param {
23 char pin[MAXSTR];
24 char rp_id[MAXSTR];
25 int ext;
26 int seed;
27 struct blob cdh;
28 struct blob cred;
29 struct blob es256;
30 struct blob rs256;
31 struct blob eddsa;
32 struct blob wire_data;
33 uint8_t cred_count;
34 uint8_t type;
35 uint8_t opt;
36 uint8_t up;
37 uint8_t uv;
38 };
39
40 /*
41 * Collection of HID reports from an authenticator issued with a FIDO2
42 * get assertion using the example parameters above.
43 */
44 static const uint8_t dummy_wire_data_fido[] = {
45 WIREDATA_CTAP_INIT,
46 WIREDATA_CTAP_CBOR_INFO,
47 WIREDATA_CTAP_CBOR_AUTHKEY,
48 WIREDATA_CTAP_CBOR_PINTOKEN,
49 WIREDATA_CTAP_CBOR_ASSERT,
50 };
51
52 /*
53 * Collection of HID reports from an authenticator issued with a U2F
54 * authentication using the example parameters above.
55 */
56 static const uint8_t dummy_wire_data_u2f[] = {
57 WIREDATA_CTAP_INIT,
58 WIREDATA_CTAP_U2F_6985,
59 WIREDATA_CTAP_U2F_6985,
60 WIREDATA_CTAP_U2F_6985,
61 WIREDATA_CTAP_U2F_6985,
62 WIREDATA_CTAP_U2F_AUTH,
63 };
64
65 struct param *
unpack(const uint8_t * ptr,size_t len)66 unpack(const uint8_t *ptr, size_t len)
67 {
68 cbor_item_t *item = NULL, **v;
69 struct cbor_load_result cbor;
70 struct param *p;
71 int ok = -1;
72
73 if ((p = calloc(1, sizeof(*p))) == NULL ||
74 (item = cbor_load(ptr, len, &cbor)) == NULL ||
75 cbor.read != len ||
76 cbor_isa_array(item) == false ||
77 cbor_array_is_definite(item) == false ||
78 cbor_array_size(item) != 15 ||
79 (v = cbor_array_handle(item)) == NULL)
80 goto fail;
81
82 if (unpack_byte(v[0], &p->uv) < 0 ||
83 unpack_byte(v[1], &p->up) < 0 ||
84 unpack_byte(v[2], &p->opt) < 0 ||
85 unpack_byte(v[3], &p->type) < 0 ||
86 unpack_byte(v[4], &p->cred_count) < 0 ||
87 unpack_int(v[5], &p->ext) < 0 ||
88 unpack_int(v[6], &p->seed) < 0 ||
89 unpack_string(v[7], p->rp_id) < 0 ||
90 unpack_string(v[8], p->pin) < 0 ||
91 unpack_blob(v[9], &p->wire_data) < 0 ||
92 unpack_blob(v[10], &p->rs256) < 0 ||
93 unpack_blob(v[11], &p->es256) < 0 ||
94 unpack_blob(v[12], &p->eddsa) < 0 ||
95 unpack_blob(v[13], &p->cred) < 0 ||
96 unpack_blob(v[14], &p->cdh) < 0)
97 goto fail;
98
99 ok = 0;
100 fail:
101 if (ok < 0) {
102 free(p);
103 p = NULL;
104 }
105
106 if (item)
107 cbor_decref(&item);
108
109 return p;
110 }
111
112 size_t
pack(uint8_t * ptr,size_t len,const struct param * p)113 pack(uint8_t *ptr, size_t len, const struct param *p)
114 {
115 cbor_item_t *argv[15], *array = NULL;
116 size_t cbor_alloc_len, cbor_len = 0;
117 unsigned char *cbor = NULL;
118
119 memset(argv, 0, sizeof(argv));
120
121 if ((array = cbor_new_definite_array(15)) == NULL ||
122 (argv[0] = pack_byte(p->uv)) == NULL ||
123 (argv[1] = pack_byte(p->up)) == NULL ||
124 (argv[2] = pack_byte(p->opt)) == NULL ||
125 (argv[3] = pack_byte(p->type)) == NULL ||
126 (argv[4] = pack_byte(p->cred_count)) == NULL ||
127 (argv[5] = pack_int(p->ext)) == NULL ||
128 (argv[6] = pack_int(p->seed)) == NULL ||
129 (argv[7] = pack_string(p->rp_id)) == NULL ||
130 (argv[8] = pack_string(p->pin)) == NULL ||
131 (argv[9] = pack_blob(&p->wire_data)) == NULL ||
132 (argv[10] = pack_blob(&p->rs256)) == NULL ||
133 (argv[11] = pack_blob(&p->es256)) == NULL ||
134 (argv[12] = pack_blob(&p->eddsa)) == NULL ||
135 (argv[13] = pack_blob(&p->cred)) == NULL ||
136 (argv[14] = pack_blob(&p->cdh)) == NULL)
137 goto fail;
138
139 for (size_t i = 0; i < 15; i++)
140 if (cbor_array_push(array, argv[i]) == false)
141 goto fail;
142
143 if ((cbor_len = cbor_serialize_alloc(array, &cbor,
144 &cbor_alloc_len)) == 0 || cbor_len > len) {
145 cbor_len = 0;
146 goto fail;
147 }
148
149 memcpy(ptr, cbor, cbor_len);
150 fail:
151 for (size_t i = 0; i < 15; i++)
152 if (argv[i])
153 cbor_decref(&argv[i]);
154
155 if (array)
156 cbor_decref(&array);
157
158 free(cbor);
159
160 return cbor_len;
161 }
162
163 size_t
pack_dummy(uint8_t * ptr,size_t len)164 pack_dummy(uint8_t *ptr, size_t len)
165 {
166 struct param dummy;
167 uint8_t blob[MAXCORPUS];
168 size_t blob_len;
169
170 memset(&dummy, 0, sizeof(dummy));
171
172 dummy.type = 1; /* rsa */
173 dummy.ext = FIDO_EXT_HMAC_SECRET;
174
175 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
176 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id));
177
178 dummy.cred.len = sizeof(dummy_cdh); /* XXX */
179 dummy.cdh.len = sizeof(dummy_cdh);
180 dummy.es256.len = sizeof(dummy_es256);
181 dummy.rs256.len = sizeof(dummy_rs256);
182 dummy.eddsa.len = sizeof(dummy_eddsa);
183 dummy.wire_data.len = sizeof(dummy_wire_data_fido);
184
185 memcpy(&dummy.cred.body, &dummy_cdh, dummy.cred.len); /* XXX */
186 memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len);
187 memcpy(&dummy.wire_data.body, &dummy_wire_data_fido,
188 dummy.wire_data.len);
189 memcpy(&dummy.es256.body, &dummy_es256, dummy.es256.len);
190 memcpy(&dummy.rs256.body, &dummy_rs256, dummy.rs256.len);
191 memcpy(&dummy.eddsa.body, &dummy_eddsa, dummy.eddsa.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
get_assert(fido_assert_t * assert,uint8_t opt,const struct blob * cdh,const char * rp_id,int ext,uint8_t up,uint8_t uv,const char * pin,uint8_t cred_count,const struct blob * cred)206 get_assert(fido_assert_t *assert, uint8_t opt, const struct blob *cdh,
207 const char *rp_id, int ext, uint8_t up, uint8_t uv, const char *pin,
208 uint8_t cred_count, const struct blob *cred)
209 {
210 fido_dev_t *dev;
211
212 if ((dev = open_dev(opt & 2)) == NULL)
213 return;
214 if (opt & 1)
215 fido_dev_force_u2f(dev);
216 if (ext & FIDO_EXT_HMAC_SECRET)
217 fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET);
218 if (ext & FIDO_EXT_CRED_BLOB)
219 fido_assert_set_extensions(assert, FIDO_EXT_CRED_BLOB);
220 if (ext & FIDO_EXT_LARGEBLOB_KEY)
221 fido_assert_set_extensions(assert, FIDO_EXT_LARGEBLOB_KEY);
222 if (up & 1)
223 fido_assert_set_up(assert, FIDO_OPT_TRUE);
224 else if (opt & 1)
225 fido_assert_set_up(assert, FIDO_OPT_FALSE);
226 if (uv & 1)
227 fido_assert_set_uv(assert, FIDO_OPT_TRUE);
228
229 for (uint8_t i = 0; i < cred_count; i++)
230 fido_assert_allow_cred(assert, cred->body, cred->len);
231
232 fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len);
233 fido_assert_set_rp(assert, rp_id);
234 /* XXX reuse cred as hmac salt */
235 fido_assert_set_hmac_salt(assert, cred->body, cred->len);
236
237 /* repeat memory operations to trigger reallocation paths */
238 fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len);
239 fido_assert_set_rp(assert, rp_id);
240 fido_assert_set_hmac_salt(assert, cred->body, cred->len);
241
242 if (strlen(pin) == 0)
243 pin = NULL;
244
245 fido_dev_get_assert(dev, assert, (opt & 1) ? NULL : pin);
246
247 fido_dev_cancel(dev);
248 fido_dev_close(dev);
249 fido_dev_free(&dev);
250 }
251
252 static void
verify_assert(int type,const unsigned char * cdh_ptr,size_t cdh_len,const char * rp_id,const unsigned char * authdata_ptr,size_t authdata_len,const unsigned char * sig_ptr,size_t sig_len,uint8_t up,uint8_t uv,int ext,void * pk)253 verify_assert(int type, const unsigned char *cdh_ptr, size_t cdh_len,
254 const char *rp_id, const unsigned char *authdata_ptr, size_t authdata_len,
255 const unsigned char *sig_ptr, size_t sig_len, uint8_t up, uint8_t uv,
256 int ext, void *pk)
257 {
258 fido_assert_t *assert = NULL;
259 int r;
260
261 if ((assert = fido_assert_new()) == NULL)
262 return;
263
264 fido_assert_set_clientdata_hash(assert, cdh_ptr, cdh_len);
265 fido_assert_set_rp(assert, rp_id);
266 fido_assert_set_count(assert, 1);
267
268 if (fido_assert_set_authdata(assert, 0, authdata_ptr,
269 authdata_len) != FIDO_OK) {
270 fido_assert_set_authdata_raw(assert, 0, authdata_ptr,
271 authdata_len);
272 }
273
274 if (up & 1)
275 fido_assert_set_up(assert, FIDO_OPT_TRUE);
276 if (uv & 1)
277 fido_assert_set_uv(assert, FIDO_OPT_TRUE);
278
279 fido_assert_set_extensions(assert, ext);
280 fido_assert_set_sig(assert, 0, sig_ptr, sig_len);
281
282 /* repeat memory operations to trigger reallocation paths */
283 if (fido_assert_set_authdata(assert, 0, authdata_ptr,
284 authdata_len) != FIDO_OK) {
285 fido_assert_set_authdata_raw(assert, 0, authdata_ptr,
286 authdata_len);
287 }
288 fido_assert_set_sig(assert, 0, sig_ptr, sig_len);
289
290 r = fido_assert_verify(assert, 0, type, pk);
291 consume(&r, sizeof(r));
292
293 fido_assert_free(&assert);
294 }
295
296 /*
297 * Do a dummy conversion to exercise es256_pk_from_EVP_PKEY().
298 */
299 static void
es256_convert(const es256_pk_t * k)300 es256_convert(const es256_pk_t *k)
301 {
302 EVP_PKEY *pkey = NULL;
303 es256_pk_t *pk = NULL;
304 int r;
305
306 if ((pkey = es256_pk_to_EVP_PKEY(k)) == NULL ||
307 (pk = es256_pk_new()) == NULL)
308 goto out;
309
310 r = es256_pk_from_EVP_PKEY(pk, pkey);
311 consume(&r, sizeof(r));
312 out:
313 es256_pk_free(&pk);
314 EVP_PKEY_free(pkey);
315 }
316
317 /*
318 * Do a dummy conversion to exercise es384_pk_from_EVP_PKEY().
319 */
320 static void
es384_convert(const es384_pk_t * k)321 es384_convert(const es384_pk_t *k)
322 {
323 EVP_PKEY *pkey = NULL;
324 es384_pk_t *pk = NULL;
325 int r;
326
327 if ((pkey = es384_pk_to_EVP_PKEY(k)) == NULL ||
328 (pk = es384_pk_new()) == NULL)
329 goto out;
330
331 r = es384_pk_from_EVP_PKEY(pk, pkey);
332 consume(&r, sizeof(r));
333 out:
334 es384_pk_free(&pk);
335 EVP_PKEY_free(pkey);
336 }
337
338 /*
339 * Do a dummy conversion to exercise rs256_pk_from_EVP_PKEY().
340 */
341 static void
rs256_convert(const rs256_pk_t * k)342 rs256_convert(const rs256_pk_t *k)
343 {
344 EVP_PKEY *pkey = NULL;
345 rs256_pk_t *pk = NULL;
346 int r;
347
348 if ((pkey = rs256_pk_to_EVP_PKEY(k)) == NULL ||
349 (pk = rs256_pk_new()) == NULL)
350 goto out;
351
352 r = rs256_pk_from_EVP_PKEY(pk, pkey);
353 consume(&r, sizeof(r));
354 out:
355 rs256_pk_free(&pk);
356 EVP_PKEY_free(pkey);
357 }
358
359 /*
360 * Do a dummy conversion to exercise eddsa_pk_from_EVP_PKEY().
361 */
362 static void
eddsa_convert(const eddsa_pk_t * k)363 eddsa_convert(const eddsa_pk_t *k)
364 {
365 EVP_PKEY *pkey = NULL;
366 eddsa_pk_t *pk = NULL;
367 int r;
368
369 if ((pkey = eddsa_pk_to_EVP_PKEY(k)) == NULL ||
370 (pk = eddsa_pk_new()) == NULL)
371 goto out;
372
373 r = eddsa_pk_from_EVP_PKEY(pk, pkey);
374 consume(&r, sizeof(r));
375 out:
376 if (pk)
377 eddsa_pk_free(&pk);
378 if (pkey)
379 EVP_PKEY_free(pkey);
380 }
381
382 void
test(const struct param * p)383 test(const struct param *p)
384 {
385 fido_assert_t *assert = NULL;
386 es256_pk_t *es256_pk = NULL;
387 es384_pk_t *es384_pk = NULL;
388 rs256_pk_t *rs256_pk = NULL;
389 eddsa_pk_t *eddsa_pk = NULL;
390 uint8_t flags;
391 uint32_t sigcount;
392 int cose_alg = 0;
393 void *pk;
394
395 prng_init((unsigned int)p->seed);
396 fuzz_clock_reset();
397 fido_init(FIDO_DEBUG);
398 fido_set_log_handler(consume_str);
399
400 switch (p->type & 3) {
401 case 0:
402 cose_alg = COSE_ES256;
403
404 if ((es256_pk = es256_pk_new()) == NULL)
405 return;
406
407 es256_pk_from_ptr(es256_pk, p->es256.body, p->es256.len);
408 pk = es256_pk;
409
410 es256_convert(pk);
411
412 break;
413 case 1:
414 cose_alg = COSE_RS256;
415
416 if ((rs256_pk = rs256_pk_new()) == NULL)
417 return;
418
419 rs256_pk_from_ptr(rs256_pk, p->rs256.body, p->rs256.len);
420 pk = rs256_pk;
421
422 rs256_convert(pk);
423
424 break;
425 case 2:
426 cose_alg = COSE_ES384;
427
428 if ((es384_pk = es384_pk_new()) == NULL)
429 return;
430
431 /* XXX reuse p->es256 as es384 */
432 es384_pk_from_ptr(es384_pk, p->es256.body, p->es256.len);
433 pk = es384_pk;
434
435 es384_convert(pk);
436
437 break;
438 default:
439 cose_alg = COSE_EDDSA;
440
441 if ((eddsa_pk = eddsa_pk_new()) == NULL)
442 return;
443
444 eddsa_pk_from_ptr(eddsa_pk, p->eddsa.body, p->eddsa.len);
445 pk = eddsa_pk;
446
447 eddsa_convert(pk);
448
449 break;
450 }
451
452 if ((assert = fido_assert_new()) == NULL)
453 goto out;
454
455 set_wire_data(p->wire_data.body, p->wire_data.len);
456
457 get_assert(assert, p->opt, &p->cdh, p->rp_id, p->ext, p->up, p->uv,
458 p->pin, p->cred_count, &p->cred);
459
460 /* XXX +1 on purpose */
461 for (size_t i = 0; i <= fido_assert_count(assert); i++) {
462 verify_assert(cose_alg,
463 fido_assert_clientdata_hash_ptr(assert),
464 fido_assert_clientdata_hash_len(assert),
465 fido_assert_rp_id(assert),
466 fido_assert_authdata_ptr(assert, i),
467 fido_assert_authdata_len(assert, i),
468 fido_assert_sig_ptr(assert, i),
469 fido_assert_sig_len(assert, i), p->up, p->uv, p->ext, pk);
470 consume(fido_assert_authdata_raw_ptr(assert, i),
471 fido_assert_authdata_raw_len(assert, i));
472 consume(fido_assert_id_ptr(assert, i),
473 fido_assert_id_len(assert, i));
474 consume(fido_assert_user_id_ptr(assert, i),
475 fido_assert_user_id_len(assert, i));
476 consume(fido_assert_hmac_secret_ptr(assert, i),
477 fido_assert_hmac_secret_len(assert, i));
478 consume_str(fido_assert_user_icon(assert, i));
479 consume_str(fido_assert_user_name(assert, i));
480 consume_str(fido_assert_user_display_name(assert, i));
481 consume(fido_assert_blob_ptr(assert, i),
482 fido_assert_blob_len(assert, i));
483 consume(fido_assert_largeblob_key_ptr(assert, i),
484 fido_assert_largeblob_key_len(assert, i));
485 flags = fido_assert_flags(assert, i);
486 consume(&flags, sizeof(flags));
487 sigcount = fido_assert_sigcount(assert, i);
488 consume(&sigcount, sizeof(sigcount));
489 }
490
491 out:
492 es256_pk_free(&es256_pk);
493 es384_pk_free(&es384_pk);
494 rs256_pk_free(&rs256_pk);
495 eddsa_pk_free(&eddsa_pk);
496
497 fido_assert_free(&assert);
498 }
499
500 void
mutate(struct param * p,unsigned int seed,unsigned int flags)501 mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
502 {
503 if (flags & MUTATE_SEED)
504 p->seed = (int)seed;
505
506 if (flags & MUTATE_PARAM) {
507 mutate_byte(&p->uv);
508 mutate_byte(&p->up);
509 mutate_byte(&p->opt);
510 mutate_byte(&p->type);
511 mutate_byte(&p->cred_count);
512 mutate_int(&p->ext);
513 mutate_blob(&p->rs256);
514 mutate_blob(&p->es256);
515 mutate_blob(&p->eddsa);
516 mutate_blob(&p->cred);
517 mutate_blob(&p->cdh);
518 mutate_string(p->rp_id);
519 mutate_string(p->pin);
520 }
521
522 if (flags & MUTATE_WIREDATA) {
523 if (p->opt & 1) {
524 p->wire_data.len = sizeof(dummy_wire_data_u2f);
525 memcpy(&p->wire_data.body, &dummy_wire_data_u2f,
526 p->wire_data.len);
527 } else {
528 p->wire_data.len = sizeof(dummy_wire_data_fido);
529 memcpy(&p->wire_data.body, &dummy_wire_data_fido,
530 p->wire_data.len);
531 }
532 mutate_blob(&p->wire_data);
533 }
534 }
535