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