Coverage Report

Created: 2025-04-22 06:18

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