1 /*
2 * Copyright (c) 2019-2021 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 /* Parameter set defining a FIDO2 credential management operation. */
21 struct param {
22 char pin[MAXSTR];
23 char rp_id[MAXSTR];
24 int seed;
25 struct blob cred_id;
26 struct blob del_wire_data;
27 struct blob meta_wire_data;
28 struct blob rk_wire_data;
29 struct blob rp_wire_data;
30 };
31
32 /*
33 * Collection of HID reports from an authenticator issued with a FIDO2
34 * 'getCredsMetadata' credential management command.
35 */
36 static const uint8_t dummy_meta_wire_data[] = {
37 WIREDATA_CTAP_INIT,
38 WIREDATA_CTAP_CBOR_INFO,
39 WIREDATA_CTAP_CBOR_AUTHKEY,
40 WIREDATA_CTAP_CBOR_PINTOKEN,
41 WIREDATA_CTAP_CBOR_CREDMAN_META,
42 };
43
44 /*
45 * Collection of HID reports from an authenticator issued with a FIDO2
46 * 'enumerateRPsBegin' credential management command.
47 */
48 static const uint8_t dummy_rp_wire_data[] = {
49 WIREDATA_CTAP_INIT,
50 WIREDATA_CTAP_CBOR_INFO,
51 WIREDATA_CTAP_CBOR_AUTHKEY,
52 WIREDATA_CTAP_CBOR_PINTOKEN,
53 WIREDATA_CTAP_CBOR_CREDMAN_RPLIST,
54 };
55
56 /*
57 * Collection of HID reports from an authenticator issued with a FIDO2
58 * 'enumerateCredentialsBegin' credential management command.
59 */
60 static const uint8_t dummy_rk_wire_data[] = {
61 WIREDATA_CTAP_INIT,
62 WIREDATA_CTAP_CBOR_INFO,
63 WIREDATA_CTAP_CBOR_AUTHKEY,
64 WIREDATA_CTAP_CBOR_PINTOKEN,
65 WIREDATA_CTAP_CBOR_CREDMAN_RKLIST,
66 };
67
68 /*
69 * Collection of HID reports from an authenticator issued with a FIDO2
70 * 'deleteCredential' credential management command.
71 */
72 static const uint8_t dummy_del_wire_data[] = {
73 WIREDATA_CTAP_INIT,
74 WIREDATA_CTAP_CBOR_INFO,
75 WIREDATA_CTAP_CBOR_AUTHKEY,
76 WIREDATA_CTAP_CBOR_PINTOKEN,
77 WIREDATA_CTAP_CBOR_STATUS,
78 };
79
80 struct param *
unpack(const uint8_t * ptr,size_t len)81 unpack(const uint8_t *ptr, size_t len)
82 {
83 cbor_item_t *item = NULL, **v;
84 struct cbor_load_result cbor;
85 struct param *p;
86 int ok = -1;
87
88 if ((p = calloc(1, sizeof(*p))) == NULL ||
89 (item = cbor_load(ptr, len, &cbor)) == NULL ||
90 cbor.read != len ||
91 cbor_isa_array(item) == false ||
92 cbor_array_is_definite(item) == false ||
93 cbor_array_size(item) != 8 ||
94 (v = cbor_array_handle(item)) == NULL)
95 goto fail;
96
97 if (unpack_int(v[0], &p->seed) < 0 ||
98 unpack_string(v[1], p->pin) < 0 ||
99 unpack_string(v[2], p->rp_id) < 0 ||
100 unpack_blob(v[3], &p->cred_id) < 0 ||
101 unpack_blob(v[4], &p->meta_wire_data) < 0 ||
102 unpack_blob(v[5], &p->rp_wire_data) < 0 ||
103 unpack_blob(v[6], &p->rk_wire_data) < 0 ||
104 unpack_blob(v[7], &p->del_wire_data) < 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
pack(uint8_t * ptr,size_t len,const struct param * p)121 pack(uint8_t *ptr, size_t len, const struct param *p)
122 {
123 cbor_item_t *argv[8], *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(8)) == NULL ||
130 (argv[0] = pack_int(p->seed)) == NULL ||
131 (argv[1] = pack_string(p->pin)) == NULL ||
132 (argv[2] = pack_string(p->rp_id)) == NULL ||
133 (argv[3] = pack_blob(&p->cred_id)) == NULL ||
134 (argv[4] = pack_blob(&p->meta_wire_data)) == NULL ||
135 (argv[5] = pack_blob(&p->rp_wire_data)) == NULL ||
136 (argv[6] = pack_blob(&p->rk_wire_data)) == NULL ||
137 (argv[7] = pack_blob(&p->del_wire_data)) == NULL)
138 goto fail;
139
140 for (size_t i = 0; i < 8; i++)
141 if (cbor_array_push(array, argv[i]) == false)
142 goto fail;
143
144 if ((cbor_len = cbor_serialize_alloc(array, &cbor,
145 &cbor_alloc_len)) == 0 || cbor_len > len) {
146 cbor_len = 0;
147 goto fail;
148 }
149
150 memcpy(ptr, cbor, cbor_len);
151 fail:
152 for (size_t i = 0; i < 8; i++)
153 if (argv[i])
154 cbor_decref(&argv[i]);
155
156 if (array)
157 cbor_decref(&array);
158
159 free(cbor);
160
161 return cbor_len;
162 }
163
164 size_t
pack_dummy(uint8_t * ptr,size_t len)165 pack_dummy(uint8_t *ptr, size_t len)
166 {
167 struct param dummy;
168 uint8_t blob[MAXCORPUS];
169 size_t blob_len;
170
171 memset(&dummy, 0, sizeof(dummy));
172
173 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
174 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id));
175
176 dummy.meta_wire_data.len = sizeof(dummy_meta_wire_data);
177 dummy.rp_wire_data.len = sizeof(dummy_rp_wire_data);
178 dummy.rk_wire_data.len = sizeof(dummy_rk_wire_data);
179 dummy.del_wire_data.len = sizeof(dummy_del_wire_data);
180 dummy.cred_id.len = sizeof(dummy_cred_id);
181
182 memcpy(&dummy.meta_wire_data.body, &dummy_meta_wire_data,
183 dummy.meta_wire_data.len);
184 memcpy(&dummy.rp_wire_data.body, &dummy_rp_wire_data,
185 dummy.rp_wire_data.len);
186 memcpy(&dummy.rk_wire_data.body, &dummy_rk_wire_data,
187 dummy.rk_wire_data.len);
188 memcpy(&dummy.del_wire_data.body, &dummy_del_wire_data,
189 dummy.del_wire_data.len);
190 memcpy(&dummy.cred_id.body, &dummy_cred_id, dummy.cred_id.len);
191
192 assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
193
194 if (blob_len > len) {
195 memcpy(ptr, blob, len);
196 return len;
197 }
198
199 memcpy(ptr, blob, blob_len);
200
201 return blob_len;
202 }
203
204 static fido_dev_t *
prepare_dev(void)205 prepare_dev(void)
206 {
207 fido_dev_t *dev;
208 bool x;
209
210 if ((dev = open_dev(0)) == NULL)
211 return NULL;
212
213 x = fido_dev_is_fido2(dev);
214 consume(&x, sizeof(x));
215 x = fido_dev_supports_cred_prot(dev);
216 consume(&x, sizeof(x));
217 x = fido_dev_supports_credman(dev);
218 consume(&x, sizeof(x));
219
220 return dev;
221 }
222
223 static void
get_metadata(const struct param * p)224 get_metadata(const struct param *p)
225 {
226 fido_dev_t *dev;
227 fido_credman_metadata_t *metadata;
228 uint64_t existing;
229 uint64_t remaining;
230
231 set_wire_data(p->meta_wire_data.body, p->meta_wire_data.len);
232
233 if ((dev = prepare_dev()) == NULL)
234 return;
235
236 if ((metadata = fido_credman_metadata_new()) == NULL) {
237 fido_dev_close(dev);
238 fido_dev_free(&dev);
239 return;
240 }
241
242 fido_credman_get_dev_metadata(dev, metadata, p->pin);
243
244 existing = fido_credman_rk_existing(metadata);
245 remaining = fido_credman_rk_remaining(metadata);
246 consume(&existing, sizeof(existing));
247 consume(&remaining, sizeof(remaining));
248
249 fido_credman_metadata_free(&metadata);
250 fido_dev_close(dev);
251 fido_dev_free(&dev);
252 }
253
254 static void
get_rp_list(const struct param * p)255 get_rp_list(const struct param *p)
256 {
257 fido_dev_t *dev;
258 fido_credman_rp_t *rp;
259
260 set_wire_data(p->rp_wire_data.body, p->rp_wire_data.len);
261
262 if ((dev = prepare_dev()) == NULL)
263 return;
264
265 if ((rp = fido_credman_rp_new()) == NULL) {
266 fido_dev_close(dev);
267 fido_dev_free(&dev);
268 return;
269 }
270
271 fido_credman_get_dev_rp(dev, rp, p->pin);
272
273 /* +1 on purpose */
274 for (size_t i = 0; i < fido_credman_rp_count(rp) + 1; i++) {
275 consume(fido_credman_rp_id_hash_ptr(rp, i),
276 fido_credman_rp_id_hash_len(rp, i));
277 consume_str(fido_credman_rp_id(rp, i));
278 consume_str(fido_credman_rp_name(rp, i));
279 }
280
281 fido_credman_rp_free(&rp);
282 fido_dev_close(dev);
283 fido_dev_free(&dev);
284 }
285
286 static void
get_rk_list(const struct param * p)287 get_rk_list(const struct param *p)
288 {
289 fido_dev_t *dev;
290 fido_credman_rk_t *rk;
291 const fido_cred_t *cred;
292 int val;
293
294 set_wire_data(p->rk_wire_data.body, p->rk_wire_data.len);
295
296 if ((dev = prepare_dev()) == NULL)
297 return;
298
299 if ((rk = fido_credman_rk_new()) == NULL) {
300 fido_dev_close(dev);
301 fido_dev_free(&dev);
302 return;
303 }
304
305 fido_credman_get_dev_rk(dev, p->rp_id, rk, p->pin);
306
307 /* +1 on purpose */
308 for (size_t i = 0; i < fido_credman_rk_count(rk) + 1; i++) {
309 if ((cred = fido_credman_rk(rk, i)) == NULL) {
310 assert(i >= fido_credman_rk_count(rk));
311 continue;
312 }
313 val = fido_cred_type(cred);
314 consume(&val, sizeof(val));
315 consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred));
316 consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred));
317 consume(fido_cred_user_id_ptr(cred),
318 fido_cred_user_id_len(cred));
319 consume_str(fido_cred_user_name(cred));
320 consume_str(fido_cred_display_name(cred));
321 val = fido_cred_prot(cred);
322 consume(&val, sizeof(val));
323 }
324
325 fido_credman_rk_free(&rk);
326 fido_dev_close(dev);
327 fido_dev_free(&dev);
328 }
329
330 static void
del_rk(const struct param * p)331 del_rk(const struct param *p)
332 {
333 fido_dev_t *dev;
334
335 set_wire_data(p->del_wire_data.body, p->del_wire_data.len);
336
337 if ((dev = prepare_dev()) == NULL)
338 return;
339
340 fido_credman_del_dev_rk(dev, p->cred_id.body, p->cred_id.len, p->pin);
341 fido_dev_close(dev);
342 fido_dev_free(&dev);
343 }
344
345 static void
set_rk(const struct param * p)346 set_rk(const struct param *p)
347 {
348 fido_dev_t *dev = NULL;
349 fido_cred_t *cred = NULL;
350 const char *pin = p->pin;
351 int r0, r1, r2;
352
353 set_wire_data(p->del_wire_data.body, p->del_wire_data.len);
354
355 if ((dev = prepare_dev()) == NULL)
356 return;
357 if ((cred = fido_cred_new()) == NULL)
358 goto out;
359 r0 = fido_cred_set_id(cred, p->cred_id.body, p->cred_id.len);
360 r1 = fido_cred_set_user(cred, p->cred_id.body, p->cred_id.len, p->rp_id,
361 NULL, NULL);
362 if (strlen(pin) == 0)
363 pin = NULL;
364 r2 = fido_credman_set_dev_rk(dev, cred, pin);
365 consume(&r0, sizeof(r0));
366 consume(&r1, sizeof(r1));
367 consume(&r2, sizeof(r2));
368 out:
369 fido_dev_close(dev);
370 fido_dev_free(&dev);
371 fido_cred_free(&cred);
372 }
373
374 void
test(const struct param * p)375 test(const struct param *p)
376 {
377 prng_init((unsigned int)p->seed);
378 fuzz_clock_reset();
379 fido_init(FIDO_DEBUG);
380 fido_set_log_handler(consume_str);
381
382 get_metadata(p);
383 get_rp_list(p);
384 get_rk_list(p);
385 del_rk(p);
386 set_rk(p);
387 }
388
389 void
mutate(struct param * p,unsigned int seed,unsigned int flags)390 mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
391 {
392 if (flags & MUTATE_SEED)
393 p->seed = (int)seed;
394
395 if (flags & MUTATE_PARAM) {
396 mutate_blob(&p->cred_id);
397 mutate_string(p->pin);
398 mutate_string(p->rp_id);
399 }
400
401 if (flags & MUTATE_WIREDATA) {
402 mutate_blob(&p->meta_wire_data);
403 mutate_blob(&p->rp_wire_data);
404 mutate_blob(&p->rk_wire_data);
405 mutate_blob(&p->del_wire_data);
406 }
407 }
408