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