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