1/*
2 * Copyright (c) 2019-2023 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. */
22struct 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 */
44static 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 */
56static 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
65struct param *
66unpack(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;
100fail:
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
112size_t
113pack(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);
150fail:
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
163size_t
164pack_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
205static void
206get_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
252static void
253verify_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 */
299static void
300es256_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));
312out:
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 */
320static void
321es384_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));
333out:
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 */
341static void
342rs256_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));
354out:
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 */
362static void
363eddsa_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));
375out:
376	if (pk)
377		eddsa_pk_free(&pk);
378	if (pkey)
379		EVP_PKEY_free(pkey);
380}
381
382void
383test(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_authdata_raw_ptr(assert, i),
471		    fido_assert_authdata_raw_len(assert, i));
472		consume(fido_assert_id_ptr(assert, i),
473		    fido_assert_id_len(assert, i));
474		consume(fido_assert_user_id_ptr(assert, i),
475		    fido_assert_user_id_len(assert, i));
476		consume(fido_assert_hmac_secret_ptr(assert, i),
477		    fido_assert_hmac_secret_len(assert, i));
478		consume_str(fido_assert_user_icon(assert, i));
479		consume_str(fido_assert_user_name(assert, i));
480		consume_str(fido_assert_user_display_name(assert, i));
481		consume(fido_assert_blob_ptr(assert, i),
482		    fido_assert_blob_len(assert, i));
483		consume(fido_assert_largeblob_key_ptr(assert, i),
484		    fido_assert_largeblob_key_len(assert, i));
485		flags = fido_assert_flags(assert, i);
486		consume(&flags, sizeof(flags));
487		sigcount = fido_assert_sigcount(assert, i);
488		consume(&sigcount, sizeof(sigcount));
489	}
490
491out:
492	es256_pk_free(&es256_pk);
493	es384_pk_free(&es384_pk);
494	rs256_pk_free(&rs256_pk);
495	eddsa_pk_free(&eddsa_pk);
496
497	fido_assert_free(&assert);
498}
499
500void
501mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
502{
503	if (flags & MUTATE_SEED)
504		p->seed = (int)seed;
505
506	if (flags & MUTATE_PARAM) {
507		mutate_byte(&p->uv);
508		mutate_byte(&p->up);
509		mutate_byte(&p->opt);
510		mutate_byte(&p->type);
511		mutate_byte(&p->cred_count);
512		mutate_int(&p->ext);
513		mutate_blob(&p->rs256);
514		mutate_blob(&p->es256);
515		mutate_blob(&p->eddsa);
516		mutate_blob(&p->cred);
517		mutate_blob(&p->cdh);
518		mutate_string(p->rp_id);
519		mutate_string(p->pin);
520	}
521
522	if (flags & MUTATE_WIREDATA) {
523		if (p->opt & 1) {
524			p->wire_data.len = sizeof(dummy_wire_data_u2f);
525			memcpy(&p->wire_data.body, &dummy_wire_data_u2f,
526			    p->wire_data.len);
527		} else {
528			p->wire_data.len = sizeof(dummy_wire_data_fido);
529			memcpy(&p->wire_data.body, &dummy_wire_data_fido,
530			    p->wire_data.len);
531		}
532		mutate_blob(&p->wire_data);
533	}
534}
535