xref: /freebsd/contrib/libfido2/fuzz/fuzz_assert.c (revision bdd1243d)
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 get assertion operation. */
21 struct param {
22 	char pin[MAXSTR];
23 	char rp_id[MAXSTR];
24 	int ext;
25 	int seed;
26 	struct blob cdh;
27 	struct blob cred;
28 	struct blob es256;
29 	struct blob rs256;
30 	struct blob eddsa;
31 	struct blob wire_data;
32 	uint8_t cred_count;
33 	uint8_t type;
34 	uint8_t opt;
35 	uint8_t up;
36 	uint8_t uv;
37 };
38 
39 /*
40  * Collection of HID reports from an authenticator issued with a FIDO2
41  * get assertion using the example parameters above.
42  */
43 static const uint8_t dummy_wire_data_fido[] = {
44 	WIREDATA_CTAP_INIT,
45 	WIREDATA_CTAP_CBOR_INFO,
46 	WIREDATA_CTAP_CBOR_AUTHKEY,
47 	WIREDATA_CTAP_CBOR_PINTOKEN,
48 	WIREDATA_CTAP_CBOR_ASSERT,
49 };
50 
51 /*
52  * Collection of HID reports from an authenticator issued with a U2F
53  * authentication using the example parameters above.
54  */
55 static const uint8_t dummy_wire_data_u2f[] = {
56 	WIREDATA_CTAP_INIT,
57 	WIREDATA_CTAP_U2F_6985,
58 	WIREDATA_CTAP_U2F_6985,
59 	WIREDATA_CTAP_U2F_6985,
60 	WIREDATA_CTAP_U2F_6985,
61 	WIREDATA_CTAP_U2F_AUTH,
62 };
63 
64 struct param *
65 unpack(const uint8_t *ptr, size_t len)
66 {
67 	cbor_item_t *item = NULL, **v;
68 	struct cbor_load_result cbor;
69 	struct param *p;
70 	int ok = -1;
71 
72 	if ((p = calloc(1, sizeof(*p))) == NULL ||
73 	    (item = cbor_load(ptr, len, &cbor)) == NULL ||
74 	    cbor.read != len ||
75 	    cbor_isa_array(item) == false ||
76 	    cbor_array_is_definite(item) == false ||
77 	    cbor_array_size(item) != 15 ||
78 	    (v = cbor_array_handle(item)) == NULL)
79 		goto fail;
80 
81 	if (unpack_byte(v[0], &p->uv) < 0 ||
82 	    unpack_byte(v[1], &p->up) < 0 ||
83 	    unpack_byte(v[2], &p->opt) < 0 ||
84 	    unpack_byte(v[3], &p->type) < 0 ||
85 	    unpack_byte(v[4], &p->cred_count) < 0 ||
86 	    unpack_int(v[5], &p->ext) < 0 ||
87 	    unpack_int(v[6], &p->seed) < 0 ||
88 	    unpack_string(v[7], p->rp_id) < 0 ||
89 	    unpack_string(v[8], p->pin) < 0 ||
90 	    unpack_blob(v[9], &p->wire_data) < 0 ||
91 	    unpack_blob(v[10], &p->rs256) < 0 ||
92 	    unpack_blob(v[11], &p->es256) < 0 ||
93 	    unpack_blob(v[12], &p->eddsa) < 0 ||
94 	    unpack_blob(v[13], &p->cred) < 0 ||
95 	    unpack_blob(v[14], &p->cdh) < 0)
96 		goto fail;
97 
98 	ok = 0;
99 fail:
100 	if (ok < 0) {
101 		free(p);
102 		p = NULL;
103 	}
104 
105 	if (item)
106 		cbor_decref(&item);
107 
108 	return p;
109 }
110 
111 size_t
112 pack(uint8_t *ptr, size_t len, const struct param *p)
113 {
114 	cbor_item_t *argv[15], *array = NULL;
115 	size_t cbor_alloc_len, cbor_len = 0;
116 	unsigned char *cbor = NULL;
117 
118 	memset(argv, 0, sizeof(argv));
119 
120 	if ((array = cbor_new_definite_array(15)) == NULL ||
121 	    (argv[0] = pack_byte(p->uv)) == NULL ||
122 	    (argv[1] = pack_byte(p->up)) == NULL ||
123 	    (argv[2] = pack_byte(p->opt)) == NULL ||
124 	    (argv[3] = pack_byte(p->type)) == NULL ||
125 	    (argv[4] = pack_byte(p->cred_count)) == NULL ||
126 	    (argv[5] = pack_int(p->ext)) == NULL ||
127 	    (argv[6] = pack_int(p->seed)) == NULL ||
128 	    (argv[7] = pack_string(p->rp_id)) == NULL ||
129 	    (argv[8] = pack_string(p->pin)) == NULL ||
130 	    (argv[9] = pack_blob(&p->wire_data)) == NULL ||
131 	    (argv[10] = pack_blob(&p->rs256)) == NULL ||
132 	    (argv[11] = pack_blob(&p->es256)) == NULL ||
133 	    (argv[12] = pack_blob(&p->eddsa)) == NULL ||
134 	    (argv[13] = pack_blob(&p->cred)) == NULL ||
135 	    (argv[14] = pack_blob(&p->cdh)) == NULL)
136 		goto fail;
137 
138 	for (size_t i = 0; i < 15; i++)
139 		if (cbor_array_push(array, argv[i]) == false)
140 			goto fail;
141 
142 	if ((cbor_len = cbor_serialize_alloc(array, &cbor,
143 	    &cbor_alloc_len)) > len) {
144 		cbor_len = 0;
145 		goto fail;
146 	}
147 
148 	memcpy(ptr, cbor, cbor_len);
149 fail:
150 	for (size_t i = 0; i < 15; i++)
151 		if (argv[i])
152 			cbor_decref(&argv[i]);
153 
154 	if (array)
155 		cbor_decref(&array);
156 
157 	free(cbor);
158 
159 	return cbor_len;
160 }
161 
162 size_t
163 pack_dummy(uint8_t *ptr, size_t len)
164 {
165 	struct param dummy;
166 	uint8_t blob[4096];
167 	size_t blob_len;
168 
169 	memset(&dummy, 0, sizeof(dummy));
170 
171 	dummy.type = 1; /* rsa */
172 	dummy.ext = FIDO_EXT_HMAC_SECRET;
173 
174 	strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
175 	strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id));
176 
177 	dummy.cred.len = sizeof(dummy_cdh); /* XXX */
178 	dummy.cdh.len = sizeof(dummy_cdh);
179 	dummy.es256.len = sizeof(dummy_es256);
180 	dummy.rs256.len = sizeof(dummy_rs256);
181 	dummy.eddsa.len = sizeof(dummy_eddsa);
182 	dummy.wire_data.len = sizeof(dummy_wire_data_fido);
183 
184 	memcpy(&dummy.cred.body, &dummy_cdh, dummy.cred.len); /* XXX */
185 	memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len);
186 	memcpy(&dummy.wire_data.body, &dummy_wire_data_fido,
187 	    dummy.wire_data.len);
188 	memcpy(&dummy.es256.body, &dummy_es256, dummy.es256.len);
189 	memcpy(&dummy.rs256.body, &dummy_rs256, dummy.rs256.len);
190 	memcpy(&dummy.eddsa.body, &dummy_eddsa, dummy.eddsa.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 void
205 get_assert(fido_assert_t *assert, uint8_t opt, const struct blob *cdh,
206     const char *rp_id, int ext, uint8_t up, uint8_t uv, const char *pin,
207     uint8_t cred_count, const struct blob *cred)
208 {
209 	fido_dev_t *dev;
210 
211 	if ((dev = open_dev(opt & 2)) == NULL)
212 		return;
213 	if (opt & 1)
214 		fido_dev_force_u2f(dev);
215 	if (ext & FIDO_EXT_HMAC_SECRET)
216 		fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET);
217 	if (ext & FIDO_EXT_CRED_BLOB)
218 		fido_assert_set_extensions(assert, FIDO_EXT_CRED_BLOB);
219 	if (ext & FIDO_EXT_LARGEBLOB_KEY)
220 		fido_assert_set_extensions(assert, FIDO_EXT_LARGEBLOB_KEY);
221 	if (up & 1)
222 		fido_assert_set_up(assert, FIDO_OPT_TRUE);
223 	else if (opt & 1)
224 		fido_assert_set_up(assert, FIDO_OPT_FALSE);
225 	if (uv & 1)
226 		fido_assert_set_uv(assert, FIDO_OPT_TRUE);
227 
228 	for (uint8_t i = 0; i < cred_count; i++)
229 		fido_assert_allow_cred(assert, cred->body, cred->len);
230 
231 	fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len);
232 	fido_assert_set_rp(assert, rp_id);
233 	/* XXX reuse cred as hmac salt */
234 	fido_assert_set_hmac_salt(assert, cred->body, cred->len);
235 
236 	/* repeat memory operations to trigger reallocation paths */
237 	fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len);
238 	fido_assert_set_rp(assert, rp_id);
239 	fido_assert_set_hmac_salt(assert, cred->body, cred->len);
240 
241 	if (strlen(pin) == 0)
242 		pin = NULL;
243 
244 	fido_dev_get_assert(dev, assert, (opt & 1) ? NULL : pin);
245 
246 	fido_dev_cancel(dev);
247 	fido_dev_close(dev);
248 	fido_dev_free(&dev);
249 }
250 
251 static void
252 verify_assert(int type, const unsigned char *cdh_ptr, size_t cdh_len,
253     const char *rp_id, const unsigned char *authdata_ptr, size_t authdata_len,
254     const unsigned char *sig_ptr, size_t sig_len, uint8_t up, uint8_t uv,
255     int ext, void *pk)
256 {
257 	fido_assert_t *assert = NULL;
258 	int r;
259 
260 	if ((assert = fido_assert_new()) == NULL)
261 		return;
262 
263 	fido_assert_set_clientdata_hash(assert, cdh_ptr, cdh_len);
264 	fido_assert_set_rp(assert, rp_id);
265 	fido_assert_set_count(assert, 1);
266 
267 	if (fido_assert_set_authdata(assert, 0, authdata_ptr,
268 	    authdata_len) != FIDO_OK) {
269 		fido_assert_set_authdata_raw(assert, 0, authdata_ptr,
270 		    authdata_len);
271 	}
272 
273 	if (up & 1)
274 		fido_assert_set_up(assert, FIDO_OPT_TRUE);
275 	if (uv & 1)
276 		fido_assert_set_uv(assert, FIDO_OPT_TRUE);
277 
278 	fido_assert_set_extensions(assert, ext);
279 	fido_assert_set_sig(assert, 0, sig_ptr, sig_len);
280 
281 	/* repeat memory operations to trigger reallocation paths */
282 	if (fido_assert_set_authdata(assert, 0, authdata_ptr,
283 	    authdata_len) != FIDO_OK) {
284 		fido_assert_set_authdata_raw(assert, 0, authdata_ptr,
285 		    authdata_len);
286 	}
287 	fido_assert_set_sig(assert, 0, sig_ptr, sig_len);
288 
289 	r = fido_assert_verify(assert, 0, type, pk);
290 	consume(&r, sizeof(r));
291 
292 	fido_assert_free(&assert);
293 }
294 
295 /*
296  * Do a dummy conversion to exercise es256_pk_from_EVP_PKEY().
297  */
298 static void
299 es256_convert(const es256_pk_t *k)
300 {
301 	EVP_PKEY *pkey = NULL;
302 	es256_pk_t *pk = NULL;
303 	int r;
304 
305 	if ((pkey = es256_pk_to_EVP_PKEY(k)) == NULL ||
306 	    (pk = es256_pk_new()) == NULL)
307 		goto out;
308 
309 	r = es256_pk_from_EVP_PKEY(pk, pkey);
310 	consume(&r, sizeof(r));
311 out:
312 	es256_pk_free(&pk);
313 	EVP_PKEY_free(pkey);
314 }
315 
316 /*
317  * Do a dummy conversion to exercise rs256_pk_from_EVP_PKEY().
318  */
319 static void
320 rs256_convert(const rs256_pk_t *k)
321 {
322 	EVP_PKEY *pkey = NULL;
323 	rs256_pk_t *pk = NULL;
324 	int r;
325 
326 	if ((pkey = rs256_pk_to_EVP_PKEY(k)) == NULL ||
327 	    (pk = rs256_pk_new()) == NULL)
328 		goto out;
329 
330 	r = rs256_pk_from_EVP_PKEY(pk, pkey);
331 	consume(&r, sizeof(r));
332 out:
333 	rs256_pk_free(&pk);
334 	EVP_PKEY_free(pkey);
335 }
336 
337 /*
338  * Do a dummy conversion to exercise eddsa_pk_from_EVP_PKEY().
339  */
340 static void
341 eddsa_convert(const eddsa_pk_t *k)
342 {
343 	EVP_PKEY *pkey = NULL;
344 	eddsa_pk_t *pk = NULL;
345 	int r;
346 
347 	if ((pkey = eddsa_pk_to_EVP_PKEY(k)) == NULL ||
348 	    (pk = eddsa_pk_new()) == NULL)
349 		goto out;
350 
351 	r = eddsa_pk_from_EVP_PKEY(pk, pkey);
352 	consume(&r, sizeof(r));
353 out:
354 	if (pk)
355 		eddsa_pk_free(&pk);
356 	if (pkey)
357 		EVP_PKEY_free(pkey);
358 }
359 
360 void
361 test(const struct param *p)
362 {
363 	fido_assert_t *assert = NULL;
364 	es256_pk_t *es256_pk = NULL;
365 	rs256_pk_t *rs256_pk = NULL;
366 	eddsa_pk_t *eddsa_pk = NULL;
367 	uint8_t flags;
368 	uint32_t sigcount;
369 	int cose_alg = 0;
370 	void *pk;
371 
372 	prng_init((unsigned int)p->seed);
373 	fuzz_clock_reset();
374 	fido_init(FIDO_DEBUG);
375 	fido_set_log_handler(consume_str);
376 
377 	switch (p->type & 3) {
378 	case 0:
379 		cose_alg = COSE_ES256;
380 
381 		if ((es256_pk = es256_pk_new()) == NULL)
382 			return;
383 
384 		es256_pk_from_ptr(es256_pk, p->es256.body, p->es256.len);
385 		pk = es256_pk;
386 
387 		es256_convert(pk);
388 
389 		break;
390 	case 1:
391 		cose_alg = COSE_RS256;
392 
393 		if ((rs256_pk = rs256_pk_new()) == NULL)
394 			return;
395 
396 		rs256_pk_from_ptr(rs256_pk, p->rs256.body, p->rs256.len);
397 		pk = rs256_pk;
398 
399 		rs256_convert(pk);
400 
401 		break;
402 	default:
403 		cose_alg = COSE_EDDSA;
404 
405 		if ((eddsa_pk = eddsa_pk_new()) == NULL)
406 			return;
407 
408 		eddsa_pk_from_ptr(eddsa_pk, p->eddsa.body, p->eddsa.len);
409 		pk = eddsa_pk;
410 
411 		eddsa_convert(pk);
412 
413 		break;
414 	}
415 
416 	if ((assert = fido_assert_new()) == NULL)
417 		goto out;
418 
419 	set_wire_data(p->wire_data.body, p->wire_data.len);
420 
421 	get_assert(assert, p->opt, &p->cdh, p->rp_id, p->ext, p->up, p->uv,
422 	    p->pin, p->cred_count, &p->cred);
423 
424 	/* XXX +1 on purpose */
425 	for (size_t i = 0; i <= fido_assert_count(assert); i++) {
426 		verify_assert(cose_alg,
427 		    fido_assert_clientdata_hash_ptr(assert),
428 		    fido_assert_clientdata_hash_len(assert),
429 		    fido_assert_rp_id(assert),
430 		    fido_assert_authdata_ptr(assert, i),
431 		    fido_assert_authdata_len(assert, i),
432 		    fido_assert_sig_ptr(assert, i),
433 		    fido_assert_sig_len(assert, i), p->up, p->uv, p->ext, pk);
434 		consume(fido_assert_id_ptr(assert, i),
435 		    fido_assert_id_len(assert, i));
436 		consume(fido_assert_user_id_ptr(assert, i),
437 		    fido_assert_user_id_len(assert, i));
438 		consume(fido_assert_hmac_secret_ptr(assert, i),
439 		    fido_assert_hmac_secret_len(assert, i));
440 		consume_str(fido_assert_user_icon(assert, i));
441 		consume_str(fido_assert_user_name(assert, i));
442 		consume_str(fido_assert_user_display_name(assert, i));
443 		consume(fido_assert_blob_ptr(assert, i),
444 		    fido_assert_blob_len(assert, i));
445 		consume(fido_assert_largeblob_key_ptr(assert, i),
446 		    fido_assert_largeblob_key_len(assert, i));
447 		flags = fido_assert_flags(assert, i);
448 		consume(&flags, sizeof(flags));
449 		sigcount = fido_assert_sigcount(assert, i);
450 		consume(&sigcount, sizeof(sigcount));
451 	}
452 
453 out:
454 	es256_pk_free(&es256_pk);
455 	rs256_pk_free(&rs256_pk);
456 	eddsa_pk_free(&eddsa_pk);
457 
458 	fido_assert_free(&assert);
459 }
460 
461 void
462 mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
463 {
464 	if (flags & MUTATE_SEED)
465 		p->seed = (int)seed;
466 
467 	if (flags & MUTATE_PARAM) {
468 		mutate_byte(&p->uv);
469 		mutate_byte(&p->up);
470 		mutate_byte(&p->opt);
471 		mutate_byte(&p->type);
472 		mutate_byte(&p->cred_count);
473 		mutate_int(&p->ext);
474 		mutate_blob(&p->rs256);
475 		mutate_blob(&p->es256);
476 		mutate_blob(&p->eddsa);
477 		mutate_blob(&p->cred);
478 		mutate_blob(&p->cdh);
479 		mutate_string(p->rp_id);
480 		mutate_string(p->pin);
481 	}
482 
483 	if (flags & MUTATE_WIREDATA) {
484 		if (p->opt & 1) {
485 			p->wire_data.len = sizeof(dummy_wire_data_u2f);
486 			memcpy(&p->wire_data.body, &dummy_wire_data_u2f,
487 			    p->wire_data.len);
488 		} else {
489 			p->wire_data.len = sizeof(dummy_wire_data_fido);
490 			memcpy(&p->wire_data.body, &dummy_wire_data_fido,
491 			    p->wire_data.len);
492 		}
493 		mutate_blob(&p->wire_data);
494 	}
495 }
496