xref: /netbsd-src/external/bsd/libfido2/dist/fuzz/fuzz_cred.c (revision 9fd8799cb5ceb66c69f2eb1a6d26a1d587ba1f1e)
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 <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 
13 #include "mutator_aux.h"
14 #include "wiredata_fido2.h"
15 #include "wiredata_u2f.h"
16 #include "dummy.h"
17 #include "fido.h"
18 
19 #include "../openbsd-compat/openbsd-compat.h"
20 
21 /* Parameter set defining a FIDO2 make credential operation. */
22 struct param {
23 	char pin[MAXSTR];
24 	char rp_id[MAXSTR];
25 	char rp_name[MAXSTR];
26 	char user_icon[MAXSTR];
27 	char user_name[MAXSTR];
28 	char user_nick[MAXSTR];
29 	int ext;
30 	int seed;
31 	struct blob cdh;
32 	struct blob excl_cred;
33 	struct blob user_id;
34 	struct blob wire_data;
35 	uint8_t excl_count;
36 	uint8_t rk;
37 	uint8_t type;
38 	uint8_t u2f;
39 	uint8_t uv;
40 };
41 
42 /*
43  * Collection of HID reports from an authenticator issued with a FIDO2
44  * make credential using the example parameters above.
45  */
46 static const uint8_t dummy_wire_data_fido[] = {
47 	WIREDATA_CTAP_INIT,
48 	WIREDATA_CTAP_CBOR_INFO,
49 	WIREDATA_CTAP_CBOR_AUTHKEY,
50 	WIREDATA_CTAP_CBOR_PINTOKEN,
51 	WIREDATA_CTAP_KEEPALIVE,
52 	WIREDATA_CTAP_KEEPALIVE,
53 	WIREDATA_CTAP_KEEPALIVE,
54 	WIREDATA_CTAP_CBOR_CRED,
55 };
56 
57 /*
58  * Collection of HID reports from an authenticator issued with a U2F
59  * registration 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_6985,
68 	WIREDATA_CTAP_U2F_REGISTER,
69 };
70 
71 struct param *
72 unpack(const uint8_t *ptr, size_t len)
73 {
74 	cbor_item_t *item = NULL, **v;
75 	struct cbor_load_result cbor;
76 	struct param *p;
77 	int ok = -1;
78 
79 	if ((p = calloc(1, sizeof(*p))) == NULL ||
80 	    (item = cbor_load(ptr, len, &cbor)) == NULL ||
81 	    cbor.read != len ||
82 	    cbor_isa_array(item) == false ||
83 	    cbor_array_is_definite(item) == false ||
84 	    cbor_array_size(item) != 17 ||
85 	    (v = cbor_array_handle(item)) == NULL)
86 		goto fail;
87 
88 	if (unpack_byte(v[0], &p->rk) < 0 ||
89 	    unpack_byte(v[1], &p->type) < 0 ||
90 	    unpack_byte(v[2], &p->u2f) < 0 ||
91 	    unpack_byte(v[3], &p->uv) < 0 ||
92 	    unpack_byte(v[4], &p->excl_count) < 0 ||
93 	    unpack_int(v[5], &p->ext) < 0 ||
94 	    unpack_int(v[6], &p->seed) < 0 ||
95 	    unpack_string(v[7], p->pin) < 0 ||
96 	    unpack_string(v[8], p->rp_id) < 0 ||
97 	    unpack_string(v[9], p->rp_name) < 0 ||
98 	    unpack_string(v[10], p->user_icon) < 0 ||
99 	    unpack_string(v[11], p->user_name) < 0 ||
100 	    unpack_string(v[12], p->user_nick) < 0 ||
101 	    unpack_blob(v[13], &p->cdh) < 0 ||
102 	    unpack_blob(v[14], &p->user_id) < 0 ||
103 	    unpack_blob(v[15], &p->wire_data) < 0 ||
104 	    unpack_blob(v[16], &p->excl_cred) < 0)
105 		goto fail;
106 
107 	ok = 0;
108 fail:
109 	if (ok < 0) {
110 		free(p);
111 		p = NULL;
112 	}
113 
114 	if (item)
115 		cbor_decref(&item);
116 
117 	return p;
118 }
119 
120 size_t
121 pack(uint8_t *ptr, size_t len, const struct param *p)
122 {
123 	cbor_item_t *argv[17], *array = NULL;
124 	size_t cbor_alloc_len, cbor_len = 0;
125 	unsigned char *cbor = NULL;
126 
127 	memset(argv, 0, sizeof(argv));
128 
129 	if ((array = cbor_new_definite_array(17)) == NULL ||
130 	    (argv[0] = pack_byte(p->rk)) == NULL ||
131 	    (argv[1] = pack_byte(p->type)) == NULL ||
132 	    (argv[2] = pack_byte(p->u2f)) == NULL ||
133 	    (argv[3] = pack_byte(p->uv)) == NULL ||
134 	    (argv[4] = pack_byte(p->excl_count)) == NULL ||
135 	    (argv[5] = pack_int(p->ext)) == NULL ||
136 	    (argv[6] = pack_int(p->seed)) == NULL ||
137 	    (argv[7] = pack_string(p->pin)) == NULL ||
138 	    (argv[8] = pack_string(p->rp_id)) == NULL ||
139 	    (argv[9] = pack_string(p->rp_name)) == NULL ||
140 	    (argv[10] = pack_string(p->user_icon)) == NULL ||
141 	    (argv[11] = pack_string(p->user_name)) == NULL ||
142 	    (argv[12] = pack_string(p->user_nick)) == NULL ||
143 	    (argv[13] = pack_blob(&p->cdh)) == NULL ||
144 	    (argv[14] = pack_blob(&p->user_id)) == NULL ||
145 	    (argv[15] = pack_blob(&p->wire_data)) == NULL ||
146 	    (argv[16] = pack_blob(&p->excl_cred)) == NULL)
147 		goto fail;
148 
149 	for (size_t i = 0; i < 17; i++)
150 		if (cbor_array_push(array, argv[i]) == false)
151 			goto fail;
152 
153 	if ((cbor_len = cbor_serialize_alloc(array, &cbor,
154 	    &cbor_alloc_len)) > len) {
155 		cbor_len = 0;
156 		goto fail;
157 	}
158 
159 	memcpy(ptr, cbor, cbor_len);
160 fail:
161 	for (size_t i = 0; i < 17; i++)
162 		if (argv[i])
163 			cbor_decref(&argv[i]);
164 
165 	if (array)
166 		cbor_decref(&array);
167 
168 	free(cbor);
169 
170 	return cbor_len;
171 }
172 
173 size_t
174 pack_dummy(uint8_t *ptr, size_t len)
175 {
176 	struct param dummy;
177 	uint8_t blob[4096];
178 	size_t blob_len;
179 
180 	memset(&dummy, 0, sizeof(dummy));
181 
182 	dummy.type = 1;
183 	dummy.ext = FIDO_EXT_HMAC_SECRET;
184 
185 	strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
186 	strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id));
187 	strlcpy(dummy.rp_name, dummy_rp_name, sizeof(dummy.rp_name));
188 	strlcpy(dummy.user_icon, dummy_user_icon, sizeof(dummy.user_icon));
189 	strlcpy(dummy.user_name, dummy_user_name, sizeof(dummy.user_name));
190 	strlcpy(dummy.user_nick, dummy_user_nick, sizeof(dummy.user_nick));
191 
192 	dummy.cdh.len = sizeof(dummy_cdh);
193 	dummy.user_id.len = sizeof(dummy_user_id);
194 	dummy.wire_data.len = sizeof(dummy_wire_data_fido);
195 
196 	memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len);
197 	memcpy(&dummy.user_id.body, &dummy_user_id, dummy.user_id.len);
198 	memcpy(&dummy.wire_data.body, &dummy_wire_data_fido,
199 	    dummy.wire_data.len);
200 
201 	assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
202 
203 	if (blob_len > len) {
204 		memcpy(ptr, blob, len);
205 		return len;
206 	}
207 
208 	memcpy(ptr, blob, blob_len);
209 
210 	return blob_len;
211 }
212 
213 static void
214 make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh,
215     const char *rp_id, const char *rp_name, const struct blob *user_id,
216     const char *user_name, const char *user_nick, const char *user_icon,
217     int ext, uint8_t rk, uint8_t uv, const char *pin, uint8_t excl_count,
218     const struct blob *excl_cred)
219 {
220 	fido_dev_t *dev;
221 	fido_dev_io_t io;
222 
223 	memset(&io, 0, sizeof(io));
224 
225 	io.open = dev_open;
226 	io.close = dev_close;
227 	io.read = dev_read;
228 	io.write = dev_write;
229 
230 	if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
231 	    &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
232 		fido_dev_free(&dev);
233 		return;
234 	}
235 
236 	if (u2f & 1)
237 		fido_dev_force_u2f(dev);
238 
239 	for (uint8_t i = 0; i < excl_count; i++)
240 		fido_cred_exclude(cred, excl_cred->body, excl_cred->len);
241 
242 	fido_cred_set_type(cred, type);
243 	fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len);
244 	fido_cred_set_rp(cred, rp_id, rp_name);
245 	fido_cred_set_user(cred, user_id->body, user_id->len, user_name,
246 	    user_nick, user_icon);
247 	fido_cred_set_extensions(cred, ext);
248 
249 	if (rk & 1)
250 		fido_cred_set_rk(cred, FIDO_OPT_TRUE);
251 	if (uv & 1)
252 		fido_cred_set_uv(cred, FIDO_OPT_TRUE);
253 	if (user_id->len)
254 		fido_cred_set_prot(cred, user_id->body[0] & 0x03);
255 
256 	/* repeat memory operations to trigger reallocation paths */
257 	fido_cred_set_type(cred, type);
258 	fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len);
259 	fido_cred_set_rp(cred, rp_id, rp_name);
260 	fido_cred_set_user(cred, user_id->body, user_id->len, user_name,
261 	    user_nick, user_icon);
262 
263 	if (strlen(pin) == 0)
264 		pin = NULL;
265 
266 	fido_dev_make_cred(dev, cred, u2f & 1 ? NULL : pin);
267 
268 	fido_dev_cancel(dev);
269 	fido_dev_close(dev);
270 	fido_dev_free(&dev);
271 }
272 
273 static void
274 verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len,
275     const char *rp_id, const char *rp_name, const unsigned char *authdata_ptr,
276     size_t authdata_len, int ext, uint8_t rk, uint8_t uv,
277     const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr,
278     size_t sig_len, const char *fmt, int prot)
279 {
280 	fido_cred_t *cred;
281 	uint8_t flags;
282 
283 	if ((cred = fido_cred_new()) == NULL)
284 		return;
285 
286 	fido_cred_set_type(cred, type);
287 	fido_cred_set_clientdata_hash(cred, cdh_ptr, cdh_len);
288 	fido_cred_set_rp(cred, rp_id, rp_name);
289 	if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK)
290 		fido_cred_set_authdata_raw(cred, authdata_ptr, authdata_len);
291 	fido_cred_set_extensions(cred, ext);
292 	fido_cred_set_x509(cred, x5c_ptr, x5c_len);
293 	fido_cred_set_sig(cred, sig_ptr, sig_len);
294 	fido_cred_set_prot(cred, prot);
295 
296 	if (rk & 1)
297 		fido_cred_set_rk(cred, FIDO_OPT_TRUE);
298 	if (uv & 1)
299 		fido_cred_set_uv(cred, FIDO_OPT_TRUE);
300 	if (fmt)
301 		fido_cred_set_fmt(cred, fmt);
302 
303 	/* repeat memory operations to trigger reallocation paths */
304 	if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK)
305 		fido_cred_set_authdata_raw(cred, authdata_ptr, authdata_len);
306 	fido_cred_set_x509(cred, x5c_ptr, x5c_len);
307 	fido_cred_set_sig(cred, sig_ptr, sig_len);
308 
309 	assert(fido_cred_verify(cred) != FIDO_OK);
310 	assert(fido_cred_verify_self(cred) != FIDO_OK);
311 
312 	consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred));
313 	consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred));
314 	consume(fido_cred_aaguid_ptr(cred), fido_cred_aaguid_len(cred));
315 	consume(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred));
316 	consume(fido_cred_user_name(cred), xstrlen(fido_cred_user_name(cred)));
317 	consume(fido_cred_display_name(cred),
318 	    xstrlen(fido_cred_display_name(cred)));
319 
320 	flags = fido_cred_flags(cred);
321 	consume(&flags, sizeof(flags));
322 	type = fido_cred_type(cred);
323 	consume(&type, sizeof(type));
324 
325 	fido_cred_free(&cred);
326 }
327 
328 static void
329 test_cred(const struct param *p)
330 {
331 	fido_cred_t *cred = NULL;
332 	int cose_alg = 0;
333 
334 	if ((cred = fido_cred_new()) == NULL)
335 		return;
336 
337 	switch (p->type & 3) {
338 	case 0:
339 		cose_alg = COSE_ES256;
340 		break;
341 	case 1:
342 		cose_alg = COSE_RS256;
343 		break;
344 	default:
345 		cose_alg = COSE_EDDSA;
346 		break;
347 	}
348 
349 	set_wire_data(p->wire_data.body, p->wire_data.len);
350 
351 	make_cred(cred, p->u2f, cose_alg, &p->cdh, p->rp_id, p->rp_name,
352 	    &p->user_id, p->user_name, p->user_nick, p->user_icon, p->ext,
353 	    p->rk, p->uv, p->pin, p->excl_count, &p->excl_cred);
354 
355 	verify_cred(cose_alg,
356 	    fido_cred_clientdata_hash_ptr(cred),
357 	    fido_cred_clientdata_hash_len(cred), fido_cred_rp_id(cred),
358 	    fido_cred_rp_name(cred), fido_cred_authdata_ptr(cred),
359 	    fido_cred_authdata_len(cred), p->ext, p->rk, p->uv,
360 	    fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred),
361 	    fido_cred_sig_ptr(cred), fido_cred_sig_len(cred),
362 	    fido_cred_fmt(cred), fido_cred_prot(cred));
363 
364 	fido_cred_free(&cred);
365 }
366 
367 static void
368 test_touch(const struct param *p)
369 {
370 	fido_dev_t *dev;
371 	fido_dev_io_t io;
372 	int r;
373 	int touched;
374 
375 	memset(&io, 0, sizeof(io));
376 
377 	io.open = dev_open;
378 	io.close = dev_close;
379 	io.read = dev_read;
380 	io.write = dev_write;
381 
382 	set_wire_data(p->wire_data.body, p->wire_data.len);
383 
384 	if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
385 	    &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
386 		fido_dev_free(&dev);
387 		return;
388 	}
389 
390 	if (p->u2f & 1)
391 		fido_dev_force_u2f(dev);
392 
393 	r = fido_dev_get_touch_begin(dev);
394 	consume_str(fido_strerr(r));
395 	r = fido_dev_get_touch_status(dev, &touched, -1);
396 	consume_str(fido_strerr(r));
397 	consume(&touched, sizeof(touched));
398 
399 	fido_dev_cancel(dev);
400 	fido_dev_close(dev);
401 	fido_dev_free(&dev);
402 }
403 
404 void
405 test(const struct param *p)
406 {
407 	prng_init((unsigned int)p->seed);
408 	fido_init(FIDO_DEBUG);
409 	fido_set_log_handler(consume_str);
410 
411 	test_cred(p);
412 	test_touch(p);
413 }
414 
415 void
416 mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
417 {
418 	if (flags & MUTATE_SEED)
419 		p->seed = (int)seed;
420 
421 	if (flags & MUTATE_PARAM) {
422 		mutate_byte(&p->rk);
423 		mutate_byte(&p->type);
424 		mutate_byte(&p->u2f);
425 		mutate_byte(&p->uv);
426 		mutate_byte(&p->excl_count);
427 		mutate_int(&p->ext);
428 		mutate_blob(&p->cdh);
429 		mutate_blob(&p->user_id);
430 		mutate_blob(&p->excl_cred);
431 		mutate_string(p->pin);
432 		mutate_string(p->user_icon);
433 		mutate_string(p->user_name);
434 		mutate_string(p->user_nick);
435 		mutate_string(p->rp_id);
436 		mutate_string(p->rp_name);
437 	}
438 
439 	if (flags & MUTATE_WIREDATA) {
440 		if (p->u2f & 1) {
441 			p->wire_data.len = sizeof(dummy_wire_data_u2f);
442 			memcpy(&p->wire_data.body, &dummy_wire_data_u2f,
443 			    p->wire_data.len);
444 		} else {
445 			p->wire_data.len = sizeof(dummy_wire_data_fido);
446 			memcpy(&p->wire_data.body, &dummy_wire_data_fido,
447 			    p->wire_data.len);
448 		}
449 		mutate_blob(&p->wire_data);
450 	}
451 }
452