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