Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libfido2/fuzz/fuzz_cred.c
39586 views
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 "wiredata_u2f.h"
17
#include "dummy.h"
18
19
#include "../openbsd-compat/openbsd-compat.h"
20
21
/* Parameter set defining a FIDO2 make credential operation. */
22
struct param {
23
char pin[MAXSTR];
24
char rp_id[MAXSTR];
25
char rp_name[MAXSTR];
26
char user_icon[MAXSTR];
27
char user_name[MAXSTR];
28
char user_nick[MAXSTR];
29
int ext;
30
int seed;
31
struct blob cdh;
32
struct blob excl_cred;
33
struct blob user_id;
34
struct blob wire_data;
35
uint8_t excl_count;
36
uint8_t rk;
37
uint8_t type;
38
uint8_t opt;
39
uint8_t uv;
40
};
41
42
/*
43
* Collection of HID reports from an authenticator issued with a FIDO2
44
* make credential using the example parameters above.
45
*/
46
static const uint8_t dummy_wire_data_fido[] = {
47
WIREDATA_CTAP_INIT,
48
WIREDATA_CTAP_CBOR_INFO,
49
WIREDATA_CTAP_CBOR_AUTHKEY,
50
WIREDATA_CTAP_CBOR_PINTOKEN,
51
WIREDATA_CTAP_KEEPALIVE,
52
WIREDATA_CTAP_KEEPALIVE,
53
WIREDATA_CTAP_KEEPALIVE,
54
WIREDATA_CTAP_CBOR_CRED,
55
};
56
57
/*
58
* Collection of HID reports from an authenticator issued with a U2F
59
* registration using the example parameters above.
60
*/
61
static const uint8_t dummy_wire_data_u2f[] = {
62
WIREDATA_CTAP_INIT,
63
WIREDATA_CTAP_U2F_6985,
64
WIREDATA_CTAP_U2F_6985,
65
WIREDATA_CTAP_U2F_6985,
66
WIREDATA_CTAP_U2F_6985,
67
WIREDATA_CTAP_U2F_6985,
68
WIREDATA_CTAP_U2F_REGISTER,
69
};
70
71
struct param *
72
unpack(const uint8_t *ptr, size_t len)
73
{
74
cbor_item_t *item = NULL, **v;
75
struct cbor_load_result cbor;
76
struct param *p;
77
int ok = -1;
78
79
if ((p = calloc(1, sizeof(*p))) == NULL ||
80
(item = cbor_load(ptr, len, &cbor)) == NULL ||
81
cbor.read != len ||
82
cbor_isa_array(item) == false ||
83
cbor_array_is_definite(item) == false ||
84
cbor_array_size(item) != 17 ||
85
(v = cbor_array_handle(item)) == NULL)
86
goto fail;
87
88
if (unpack_byte(v[0], &p->rk) < 0 ||
89
unpack_byte(v[1], &p->type) < 0 ||
90
unpack_byte(v[2], &p->opt) < 0 ||
91
unpack_byte(v[3], &p->uv) < 0 ||
92
unpack_byte(v[4], &p->excl_count) < 0 ||
93
unpack_int(v[5], &p->ext) < 0 ||
94
unpack_int(v[6], &p->seed) < 0 ||
95
unpack_string(v[7], p->pin) < 0 ||
96
unpack_string(v[8], p->rp_id) < 0 ||
97
unpack_string(v[9], p->rp_name) < 0 ||
98
unpack_string(v[10], p->user_icon) < 0 ||
99
unpack_string(v[11], p->user_name) < 0 ||
100
unpack_string(v[12], p->user_nick) < 0 ||
101
unpack_blob(v[13], &p->cdh) < 0 ||
102
unpack_blob(v[14], &p->user_id) < 0 ||
103
unpack_blob(v[15], &p->wire_data) < 0 ||
104
unpack_blob(v[16], &p->excl_cred) < 0)
105
goto fail;
106
107
ok = 0;
108
fail:
109
if (ok < 0) {
110
free(p);
111
p = NULL;
112
}
113
114
if (item)
115
cbor_decref(&item);
116
117
return p;
118
}
119
120
size_t
121
pack(uint8_t *ptr, size_t len, const struct param *p)
122
{
123
cbor_item_t *argv[17], *array = NULL;
124
size_t cbor_alloc_len, cbor_len = 0;
125
unsigned char *cbor = NULL;
126
127
memset(argv, 0, sizeof(argv));
128
129
if ((array = cbor_new_definite_array(17)) == NULL ||
130
(argv[0] = pack_byte(p->rk)) == NULL ||
131
(argv[1] = pack_byte(p->type)) == NULL ||
132
(argv[2] = pack_byte(p->opt)) == NULL ||
133
(argv[3] = pack_byte(p->uv)) == NULL ||
134
(argv[4] = pack_byte(p->excl_count)) == NULL ||
135
(argv[5] = pack_int(p->ext)) == NULL ||
136
(argv[6] = pack_int(p->seed)) == NULL ||
137
(argv[7] = pack_string(p->pin)) == NULL ||
138
(argv[8] = pack_string(p->rp_id)) == NULL ||
139
(argv[9] = pack_string(p->rp_name)) == NULL ||
140
(argv[10] = pack_string(p->user_icon)) == NULL ||
141
(argv[11] = pack_string(p->user_name)) == NULL ||
142
(argv[12] = pack_string(p->user_nick)) == NULL ||
143
(argv[13] = pack_blob(&p->cdh)) == NULL ||
144
(argv[14] = pack_blob(&p->user_id)) == NULL ||
145
(argv[15] = pack_blob(&p->wire_data)) == NULL ||
146
(argv[16] = pack_blob(&p->excl_cred)) == NULL)
147
goto fail;
148
149
for (size_t i = 0; i < 17; i++)
150
if (cbor_array_push(array, argv[i]) == false)
151
goto fail;
152
153
if ((cbor_len = cbor_serialize_alloc(array, &cbor,
154
&cbor_alloc_len)) == 0 || cbor_len > len) {
155
cbor_len = 0;
156
goto fail;
157
}
158
159
memcpy(ptr, cbor, cbor_len);
160
fail:
161
for (size_t i = 0; i < 17; i++)
162
if (argv[i])
163
cbor_decref(&argv[i]);
164
165
if (array)
166
cbor_decref(&array);
167
168
free(cbor);
169
170
return cbor_len;
171
}
172
173
size_t
174
pack_dummy(uint8_t *ptr, size_t len)
175
{
176
struct param dummy;
177
uint8_t blob[MAXCORPUS];
178
size_t blob_len;
179
180
memset(&dummy, 0, sizeof(dummy));
181
182
dummy.type = 1;
183
dummy.ext = FIDO_EXT_HMAC_SECRET;
184
185
strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
186
strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id));
187
strlcpy(dummy.rp_name, dummy_rp_name, sizeof(dummy.rp_name));
188
strlcpy(dummy.user_icon, dummy_user_icon, sizeof(dummy.user_icon));
189
strlcpy(dummy.user_name, dummy_user_name, sizeof(dummy.user_name));
190
strlcpy(dummy.user_nick, dummy_user_nick, sizeof(dummy.user_nick));
191
192
dummy.cdh.len = sizeof(dummy_cdh);
193
dummy.user_id.len = sizeof(dummy_user_id);
194
dummy.wire_data.len = sizeof(dummy_wire_data_fido);
195
196
memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len);
197
memcpy(&dummy.user_id.body, &dummy_user_id, dummy.user_id.len);
198
memcpy(&dummy.wire_data.body, &dummy_wire_data_fido,
199
dummy.wire_data.len);
200
201
assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
202
203
if (blob_len > len) {
204
memcpy(ptr, blob, len);
205
return len;
206
}
207
208
memcpy(ptr, blob, blob_len);
209
210
return blob_len;
211
}
212
213
static void
214
make_cred(fido_cred_t *cred, uint8_t opt, int type, const struct blob *cdh,
215
const char *rp_id, const char *rp_name, const struct blob *user_id,
216
const char *user_name, const char *user_nick, const char *user_icon,
217
int ext, uint8_t rk, uint8_t uv, const char *pin, uint8_t excl_count,
218
const struct blob *excl_cred)
219
{
220
fido_dev_t *dev;
221
222
if ((dev = open_dev(opt & 2)) == NULL)
223
return;
224
if (opt & 1)
225
fido_dev_force_u2f(dev);
226
227
for (uint8_t i = 0; i < excl_count; i++)
228
fido_cred_exclude(cred, excl_cred->body, excl_cred->len);
229
230
fido_cred_set_type(cred, type);
231
fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len);
232
fido_cred_set_rp(cred, rp_id, rp_name);
233
fido_cred_set_user(cred, user_id->body, user_id->len, user_name,
234
user_nick, user_icon);
235
236
if (ext & FIDO_EXT_HMAC_SECRET)
237
fido_cred_set_extensions(cred, FIDO_EXT_HMAC_SECRET);
238
if (ext & FIDO_EXT_CRED_BLOB)
239
fido_cred_set_blob(cred, user_id->body, user_id->len);
240
if (ext & FIDO_EXT_LARGEBLOB_KEY)
241
fido_cred_set_extensions(cred, FIDO_EXT_LARGEBLOB_KEY);
242
if (ext & FIDO_EXT_MINPINLEN)
243
fido_cred_set_pin_minlen(cred, strlen(pin));
244
245
if (rk & 1)
246
fido_cred_set_rk(cred, FIDO_OPT_TRUE);
247
if (uv & 1)
248
fido_cred_set_uv(cred, FIDO_OPT_TRUE);
249
if (user_id->len)
250
fido_cred_set_prot(cred, user_id->body[0] & 0x03);
251
252
/* repeat memory operations to trigger reallocation paths */
253
fido_cred_set_type(cred, type);
254
fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len);
255
fido_cred_set_rp(cred, rp_id, rp_name);
256
fido_cred_set_user(cred, user_id->body, user_id->len, user_name,
257
user_nick, user_icon);
258
259
if (strlen(pin) == 0)
260
pin = NULL;
261
262
fido_dev_make_cred(dev, cred, (opt & 1) ? NULL : pin);
263
264
fido_dev_cancel(dev);
265
fido_dev_close(dev);
266
fido_dev_free(&dev);
267
}
268
269
static void
270
verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len,
271
const char *rp_id, const char *rp_name, const unsigned char *authdata_ptr,
272
size_t authdata_len, const unsigned char *authdata_raw_ptr,
273
size_t authdata_raw_len, int ext, uint8_t rk, uint8_t uv,
274
const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr,
275
size_t sig_len, const unsigned char *attstmt_ptr, size_t attstmt_len,
276
const char *fmt, int prot, size_t minpinlen)
277
{
278
fido_cred_t *cred;
279
uint8_t flags;
280
uint32_t sigcount;
281
int r;
282
283
if ((cred = fido_cred_new()) == NULL)
284
return;
285
286
fido_cred_set_type(cred, type);
287
fido_cred_set_clientdata_hash(cred, cdh_ptr, cdh_len);
288
fido_cred_set_rp(cred, rp_id, rp_name);
289
consume(authdata_ptr, authdata_len);
290
consume(authdata_raw_ptr, authdata_raw_len);
291
consume(x5c_ptr, x5c_len);
292
consume(sig_ptr, sig_len);
293
consume(attstmt_ptr, attstmt_len);
294
if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK)
295
fido_cred_set_authdata_raw(cred, authdata_raw_ptr,
296
authdata_raw_len);
297
fido_cred_set_extensions(cred, ext);
298
if (fido_cred_set_attstmt(cred, attstmt_ptr, attstmt_len) != FIDO_OK) {
299
fido_cred_set_x509(cred, x5c_ptr, x5c_len);
300
fido_cred_set_sig(cred, sig_ptr, sig_len);
301
}
302
fido_cred_set_prot(cred, prot);
303
fido_cred_set_pin_minlen(cred, minpinlen);
304
305
if (rk & 1)
306
fido_cred_set_rk(cred, FIDO_OPT_TRUE);
307
if (uv & 1)
308
fido_cred_set_uv(cred, FIDO_OPT_TRUE);
309
if (fmt)
310
fido_cred_set_fmt(cred, fmt);
311
312
/* repeat memory operations to trigger reallocation paths */
313
if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK)
314
fido_cred_set_authdata_raw(cred, authdata_raw_ptr,
315
authdata_raw_len);
316
if (fido_cred_set_attstmt(cred, attstmt_ptr, attstmt_len) != FIDO_OK) {
317
fido_cred_set_x509(cred, x5c_ptr, x5c_len);
318
fido_cred_set_sig(cred, sig_ptr, sig_len);
319
}
320
fido_cred_set_x509(cred, x5c_ptr, x5c_len);
321
fido_cred_set_sig(cred, sig_ptr, sig_len);
322
323
r = fido_cred_verify(cred);
324
consume(&r, sizeof(r));
325
r = fido_cred_verify_self(cred);
326
consume(&r, sizeof(r));
327
328
consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred));
329
consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred));
330
consume(fido_cred_aaguid_ptr(cred), fido_cred_aaguid_len(cred));
331
consume(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred));
332
consume_str(fido_cred_user_name(cred));
333
consume_str(fido_cred_display_name(cred));
334
consume(fido_cred_largeblob_key_ptr(cred),
335
fido_cred_largeblob_key_len(cred));
336
337
flags = fido_cred_flags(cred);
338
consume(&flags, sizeof(flags));
339
sigcount = fido_cred_sigcount(cred);
340
consume(&sigcount, sizeof(sigcount));
341
type = fido_cred_type(cred);
342
consume(&type, sizeof(type));
343
minpinlen = fido_cred_pin_minlen(cred);
344
consume(&minpinlen, sizeof(minpinlen));
345
346
fido_cred_free(&cred);
347
}
348
349
static void
350
test_cred(const struct param *p)
351
{
352
fido_cred_t *cred = NULL;
353
int cose_alg = 0;
354
355
if ((cred = fido_cred_new()) == NULL)
356
return;
357
358
switch (p->type & 3) {
359
case 0:
360
cose_alg = COSE_ES256;
361
break;
362
case 1:
363
cose_alg = COSE_RS256;
364
break;
365
case 2:
366
cose_alg = COSE_ES384;
367
break;
368
default:
369
cose_alg = COSE_EDDSA;
370
break;
371
}
372
373
set_wire_data(p->wire_data.body, p->wire_data.len);
374
375
make_cred(cred, p->opt, cose_alg, &p->cdh, p->rp_id, p->rp_name,
376
&p->user_id, p->user_name, p->user_nick, p->user_icon, p->ext,
377
p->rk, p->uv, p->pin, p->excl_count, &p->excl_cred);
378
379
verify_cred(cose_alg,
380
fido_cred_clientdata_hash_ptr(cred),
381
fido_cred_clientdata_hash_len(cred), fido_cred_rp_id(cred),
382
fido_cred_rp_name(cred), fido_cred_authdata_ptr(cred),
383
fido_cred_authdata_len(cred), fido_cred_authdata_raw_ptr(cred),
384
fido_cred_authdata_raw_len(cred), p->ext, p->rk, p->uv,
385
fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred),
386
fido_cred_sig_ptr(cred), fido_cred_sig_len(cred),
387
fido_cred_attstmt_ptr(cred), fido_cred_attstmt_len(cred),
388
fido_cred_fmt(cred), fido_cred_prot(cred),
389
fido_cred_pin_minlen(cred));
390
391
fido_cred_free(&cred);
392
}
393
394
static void
395
test_touch(const struct param *p)
396
{
397
fido_dev_t *dev;
398
int r;
399
int touched;
400
401
set_wire_data(p->wire_data.body, p->wire_data.len);
402
403
if ((dev = open_dev(p->opt & 2)) == NULL)
404
return;
405
if (p->opt & 1)
406
fido_dev_force_u2f(dev);
407
408
r = fido_dev_get_touch_begin(dev);
409
consume_str(fido_strerr(r));
410
r = fido_dev_get_touch_status(dev, &touched, -1);
411
consume_str(fido_strerr(r));
412
consume(&touched, sizeof(touched));
413
414
fido_dev_cancel(dev);
415
fido_dev_close(dev);
416
fido_dev_free(&dev);
417
}
418
419
static void
420
test_misc(const struct param *p)
421
{
422
fido_cred_t *cred = NULL;
423
424
if ((cred = fido_cred_new()) == NULL)
425
return;
426
427
/* reuse user id as credential id */
428
fido_cred_set_id(cred, p->user_id.body, p->user_id.len);
429
consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred));
430
fido_cred_free(&cred);
431
}
432
433
void
434
test(const struct param *p)
435
{
436
prng_init((unsigned int)p->seed);
437
fuzz_clock_reset();
438
fido_init(FIDO_DEBUG);
439
fido_set_log_handler(consume_str);
440
441
test_cred(p);
442
test_touch(p);
443
test_misc(p);
444
}
445
446
void
447
mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
448
{
449
if (flags & MUTATE_SEED)
450
p->seed = (int)seed;
451
452
if (flags & MUTATE_PARAM) {
453
mutate_byte(&p->rk);
454
mutate_byte(&p->type);
455
mutate_byte(&p->opt);
456
mutate_byte(&p->uv);
457
mutate_byte(&p->excl_count);
458
mutate_int(&p->ext);
459
mutate_blob(&p->cdh);
460
mutate_blob(&p->user_id);
461
mutate_blob(&p->excl_cred);
462
mutate_string(p->pin);
463
mutate_string(p->user_icon);
464
mutate_string(p->user_name);
465
mutate_string(p->user_nick);
466
mutate_string(p->rp_id);
467
mutate_string(p->rp_name);
468
}
469
470
if (flags & MUTATE_WIREDATA) {
471
if (p->opt & 1) {
472
p->wire_data.len = sizeof(dummy_wire_data_u2f);
473
memcpy(&p->wire_data.body, &dummy_wire_data_u2f,
474
p->wire_data.len);
475
} else {
476
p->wire_data.len = sizeof(dummy_wire_data_fido);
477
memcpy(&p->wire_data.body, &dummy_wire_data_fido,
478
p->wire_data.len);
479
}
480
mutate_blob(&p->wire_data);
481
}
482
}
483
484