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