xref: /netbsd-src/external/bsd/libfido2/dist/fuzz/fuzz_cred.c (revision cef8759bd76c1b621f8eab8faa6f208faabc2e15)
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 #define TAG_U2F		0x01
22 #define TAG_TYPE	0x02
23 #define TAG_CDH		0x03
24 #define TAG_RP_ID	0x04
25 #define TAG_RP_NAME	0x05
26 #define TAG_USER_ID	0x06
27 #define TAG_USER_NAME	0x07
28 #define TAG_USER_NICK	0x08
29 #define TAG_USER_ICON	0x09
30 #define TAG_EXT		0x0a
31 #define TAG_SEED	0x0b
32 #define TAG_RK		0x0c
33 #define TAG_UV		0x0d
34 #define TAG_PIN		0x0e
35 #define TAG_WIRE_DATA	0x0f
36 #define TAG_EXCL_COUNT	0x10
37 #define TAG_EXCL_CRED	0x11
38 
39 /* Parameter set defining a FIDO2 make credential operation. */
40 struct param {
41 	char		pin[MAXSTR];
42 	char		rp_id[MAXSTR];
43 	char		rp_name[MAXSTR];
44 	char		user_icon[MAXSTR];
45 	char		user_name[MAXSTR];
46 	char		user_nick[MAXSTR];
47 	int		ext;
48 	int		seed;
49 	struct blob	cdh;
50 	struct blob	excl_cred;
51 	struct blob	user_id;
52 	struct blob	wire_data;
53 	uint8_t		excl_count;
54 	uint8_t		rk;
55 	uint8_t		type;
56 	uint8_t		u2f;
57 	uint8_t		uv;
58 };
59 
60 /*
61  * Collection of HID reports from an authenticator issued with a FIDO2
62  * make credential using the example parameters above.
63  */
64 static const uint8_t dummy_wire_data_fido[] = {
65 	WIREDATA_CTAP_INIT,
66 	WIREDATA_CTAP_CBOR_INFO,
67 	WIREDATA_CTAP_CBOR_AUTHKEY,
68 	WIREDATA_CTAP_CBOR_PINTOKEN,
69 	WIREDATA_CTAP_KEEPALIVE,
70 	WIREDATA_CTAP_KEEPALIVE,
71 	WIREDATA_CTAP_KEEPALIVE,
72 	WIREDATA_CTAP_CBOR_CRED,
73 };
74 
75 /*
76  * Collection of HID reports from an authenticator issued with a U2F
77  * registration using the example parameters above.
78  */
79 static const uint8_t dummy_wire_data_u2f[] = {
80 	WIREDATA_CTAP_INIT,
81 	WIREDATA_CTAP_U2F_6985,
82 	WIREDATA_CTAP_U2F_6985,
83 	WIREDATA_CTAP_U2F_6985,
84 	WIREDATA_CTAP_U2F_6985,
85 	WIREDATA_CTAP_U2F_6985,
86 	WIREDATA_CTAP_U2F_REGISTER,
87 };
88 
89 int    LLVMFuzzerTestOneInput(const uint8_t *, size_t);
90 size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int);
91 
92 static int
93 unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN
94 {
95 	uint8_t **pp = (void *)&ptr;
96 
97 	if (unpack_byte(TAG_RK, pp, &len, &p->rk) < 0 ||
98 	    unpack_byte(TAG_TYPE, pp, &len, &p->type) < 0 ||
99 	    unpack_byte(TAG_U2F, pp, &len, &p->u2f) < 0 ||
100 	    unpack_byte(TAG_UV, pp, &len, &p->uv) < 0 ||
101 	    unpack_byte(TAG_EXCL_COUNT, pp, &len, &p->excl_count) < 0 ||
102 	    unpack_string(TAG_PIN, pp, &len, p->pin) < 0 ||
103 	    unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 ||
104 	    unpack_string(TAG_RP_NAME, pp, &len, p->rp_name) < 0 ||
105 	    unpack_string(TAG_USER_ICON, pp, &len, p->user_icon) < 0 ||
106 	    unpack_string(TAG_USER_NAME, pp, &len, p->user_name) < 0 ||
107 	    unpack_string(TAG_USER_NICK, pp, &len, p->user_nick) < 0 ||
108 	    unpack_int(TAG_EXT, pp, &len, &p->ext) < 0 ||
109 	    unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 ||
110 	    unpack_blob(TAG_CDH, pp, &len, &p->cdh) < 0 ||
111 	    unpack_blob(TAG_USER_ID, pp, &len, &p->user_id) < 0 ||
112 	    unpack_blob(TAG_WIRE_DATA, pp, &len, &p->wire_data) < 0 ||
113 	    unpack_blob(TAG_EXCL_CRED, pp, &len, &p->excl_cred) < 0)
114 		return (-1);
115 
116 	return (0);
117 }
118 
119 static size_t
120 pack(uint8_t *ptr, size_t len, const struct param *p)
121 {
122 	const size_t max = len;
123 
124 	if (pack_byte(TAG_RK, &ptr, &len, p->rk) < 0 ||
125 	    pack_byte(TAG_TYPE, &ptr, &len, p->type) < 0 ||
126 	    pack_byte(TAG_U2F, &ptr, &len, p->u2f) < 0 ||
127 	    pack_byte(TAG_UV, &ptr, &len, p->uv) < 0 ||
128 	    pack_byte(TAG_EXCL_COUNT, &ptr, &len, p->excl_count) < 0 ||
129 	    pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 ||
130 	    pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 ||
131 	    pack_string(TAG_RP_NAME, &ptr, &len, p->rp_name) < 0 ||
132 	    pack_string(TAG_USER_ICON, &ptr, &len, p->user_icon) < 0 ||
133 	    pack_string(TAG_USER_NAME, &ptr, &len, p->user_name) < 0 ||
134 	    pack_string(TAG_USER_NICK, &ptr, &len, p->user_nick) < 0 ||
135 	    pack_int(TAG_EXT, &ptr, &len, p->ext) < 0 ||
136 	    pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 ||
137 	    pack_blob(TAG_CDH, &ptr, &len, &p->cdh) < 0 ||
138 	    pack_blob(TAG_USER_ID, &ptr, &len, &p->user_id) < 0 ||
139 	    pack_blob(TAG_WIRE_DATA, &ptr, &len, &p->wire_data) < 0 ||
140 	    pack_blob(TAG_EXCL_CRED, &ptr, &len, &p->excl_cred) < 0)
141 		return (0);
142 
143 	return (max - len);
144 }
145 
146 static size_t
147 input_len(int max)
148 {
149 	return (5 * len_byte() + 6 * len_string(max) + 2 * len_int() +
150 	    4 * len_blob(max));
151 }
152 
153 static void
154 make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh,
155     const char *rp_id, const char *rp_name, struct blob *user_id,
156     const char *user_name, const char *user_nick, const char *user_icon,
157     int ext, uint8_t rk, uint8_t uv, const char *pin, uint8_t excl_count,
158     struct blob *excl_cred)
159 {
160 	fido_dev_t	*dev;
161 	fido_dev_io_t	 io;
162 
163 	memset(&io, 0, sizeof(io));
164 
165 	io.open = dev_open;
166 	io.close = dev_close;
167 	io.read = dev_read;
168 	io.write = dev_write;
169 
170 	if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
171 	    &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
172 		fido_dev_free(&dev);
173 		return;
174 	}
175 
176 	if (u2f & 1)
177 		fido_dev_force_u2f(dev);
178 
179 	for (uint8_t i = 0; i < excl_count; i++)
180 		fido_cred_exclude(cred, excl_cred->body, excl_cred->len);
181 
182 	fido_cred_set_type(cred, type);
183 	fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len);
184 	fido_cred_set_rp(cred, rp_id, rp_name);
185 	fido_cred_set_user(cred, user_id->body, user_id->len, user_name,
186 	    user_nick, user_icon);
187 	fido_cred_set_extensions(cred, ext);
188 	if (rk & 1)
189 		fido_cred_set_rk(cred, FIDO_OPT_TRUE);
190 	if (uv & 1)
191 		fido_cred_set_uv(cred, FIDO_OPT_TRUE);
192 	if (user_id->len)
193 		fido_cred_set_prot(cred, user_id->body[0] & 0x03);
194 
195 	fido_dev_make_cred(dev, cred, u2f & 1 ? NULL : pin);
196 
197 	fido_dev_cancel(dev);
198 	fido_dev_close(dev);
199 	fido_dev_free(&dev);
200 }
201 
202 static void
203 verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len,
204     const char *rp_id, const char *rp_name, const unsigned char *authdata_ptr,
205     size_t authdata_len, int ext, uint8_t rk, uint8_t uv,
206     const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr,
207     size_t sig_len, const char *fmt, int prot)
208 {
209 	fido_cred_t	*cred;
210 	uint8_t		 flags;
211 
212 	if ((cred = fido_cred_new()) == NULL)
213 		return;
214 
215 	fido_cred_set_type(cred, type);
216 	fido_cred_set_clientdata_hash(cred, cdh_ptr, cdh_len);
217 	fido_cred_set_rp(cred, rp_id, rp_name);
218 	if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK)
219 		fido_cred_set_authdata_raw(cred, authdata_ptr, authdata_len);
220 	fido_cred_set_extensions(cred, ext);
221 	fido_cred_set_x509(cred, x5c_ptr, x5c_len);
222 	fido_cred_set_sig(cred, sig_ptr, sig_len);
223 	fido_cred_set_prot(cred, prot);
224 
225 	if (rk & 1)
226 		fido_cred_set_rk(cred, FIDO_OPT_TRUE);
227 	if (uv & 1)
228 		fido_cred_set_uv(cred, FIDO_OPT_TRUE);
229 	if (fmt)
230 		fido_cred_set_fmt(cred, fmt);
231 
232 	fido_cred_verify(cred);
233 	fido_cred_verify_self(cred);
234 
235 	consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred));
236 	consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred));
237 	consume(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred));
238 	consume(fido_cred_user_name(cred), xstrlen(fido_cred_user_name(cred)));
239 	consume(fido_cred_display_name(cred),
240 	    xstrlen(fido_cred_display_name(cred)));
241 
242 	flags = fido_cred_flags(cred);
243 	consume(&flags, sizeof(flags));
244 	type = fido_cred_type(cred);
245 	consume(&type, sizeof(type));
246 
247 	fido_cred_free(&cred);
248 }
249 
250 int
251 LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
252 {
253 	struct param	 p;
254 	fido_cred_t	*cred = NULL;
255 	int		 cose_alg = 0;
256 
257 	memset(&p, 0, sizeof(p));
258 
259 	if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) ||
260 	    unpack(data, size, &p) < 0)
261 		return (0);
262 
263 	prng_init((unsigned int)p.seed);
264 
265 	fido_init(FIDO_DEBUG);
266 	fido_set_log_handler(consume_str);
267 
268 	if ((cred = fido_cred_new()) == NULL)
269 		return (0);
270 
271 	set_wire_data(p.wire_data.body, p.wire_data.len);
272 
273 	switch (p.type & 3) {
274 	case 0:
275 		cose_alg = COSE_ES256;
276 		break;
277 	case 1:
278 		cose_alg = COSE_RS256;
279 		break;
280 	default:
281 		cose_alg = COSE_EDDSA;
282 		break;
283 	}
284 
285 	make_cred(cred, p.u2f, cose_alg, &p.cdh, p.rp_id, p.rp_name,
286 	    &p.user_id, p.user_name, p.user_nick, p.user_icon, p.ext, p.rk,
287 	    p.uv, p.pin, p.excl_count, &p.excl_cred);
288 
289 	verify_cred(cose_alg,
290 	    fido_cred_clientdata_hash_ptr(cred),
291 	    fido_cred_clientdata_hash_len(cred), fido_cred_rp_id(cred),
292 	    fido_cred_rp_name(cred), fido_cred_authdata_ptr(cred),
293 	    fido_cred_authdata_len(cred), p.ext, p.rk, p.uv,
294 	    fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred),
295 	    fido_cred_sig_ptr(cred), fido_cred_sig_len(cred),
296 	    fido_cred_fmt(cred), fido_cred_prot(cred));
297 
298 	fido_cred_free(&cred);
299 
300 	return (0);
301 }
302 
303 static size_t
304 pack_dummy(uint8_t *ptr, size_t len)
305 {
306 	struct param	dummy;
307 	uint8_t		blob[16384];
308 	size_t		blob_len;
309 
310 	memset(&dummy, 0, sizeof(dummy));
311 
312 	dummy.type = 1;
313 	dummy.ext = FIDO_EXT_HMAC_SECRET;
314 
315 	strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
316 	strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id));
317 	strlcpy(dummy.rp_name, dummy_rp_name, sizeof(dummy.rp_name));
318 	strlcpy(dummy.user_icon, dummy_user_icon, sizeof(dummy.user_icon));
319 	strlcpy(dummy.user_name, dummy_user_name, sizeof(dummy.user_name));
320 	strlcpy(dummy.user_nick, dummy_user_nick, sizeof(dummy.user_nick));
321 
322 	dummy.cdh.len = sizeof(dummy_cdh);
323 	dummy.user_id.len = sizeof(dummy_user_id);
324 	dummy.wire_data.len = sizeof(dummy_wire_data_fido);
325 
326 	memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len);
327 	memcpy(&dummy.user_id.body, &dummy_user_id, dummy.user_id.len);
328 	memcpy(&dummy.wire_data.body, &dummy_wire_data_fido,
329 	    dummy.wire_data.len);
330 
331 	blob_len = pack(blob, sizeof(blob), &dummy);
332 	assert(blob_len != 0);
333 
334 	if (blob_len > len) {
335 		memcpy(ptr, blob, len);
336 		return (len);
337 	}
338 
339 	memcpy(ptr, blob, blob_len);
340 
341 	return (blob_len);
342 }
343 
344 size_t
345 LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize,
346     unsigned int seed) NO_MSAN
347 {
348 	struct param	p;
349 	uint8_t		blob[16384];
350 	size_t		blob_len;
351 
352 	memset(&p, 0, sizeof(p));
353 
354 	if (unpack(data, size, &p) < 0)
355 		return (pack_dummy(data, maxsize));
356 
357 	mutate_byte(&p.rk);
358 	mutate_byte(&p.type);
359 	mutate_byte(&p.u2f);
360 	mutate_byte(&p.uv);
361 	mutate_byte(&p.excl_count);
362 
363 	mutate_int(&p.ext);
364 	p.seed = (int)seed;
365 
366 	mutate_blob(&p.cdh);
367 	mutate_blob(&p.user_id);
368 
369 	if (p.u2f & 1) {
370 		p.wire_data.len = sizeof(dummy_wire_data_u2f);
371 		memcpy(&p.wire_data.body, &dummy_wire_data_u2f,
372 		    p.wire_data.len);
373 	} else {
374 		p.wire_data.len = sizeof(dummy_wire_data_fido);
375 		memcpy(&p.wire_data.body, &dummy_wire_data_fido,
376 		    p.wire_data.len);
377 	}
378 
379 	mutate_blob(&p.wire_data);
380 	mutate_blob(&p.excl_cred);
381 
382 	mutate_string(p.pin);
383 	mutate_string(p.user_icon);
384 	mutate_string(p.user_name);
385 	mutate_string(p.user_nick);
386 	mutate_string(p.rp_id);
387 	mutate_string(p.rp_name);
388 
389 	blob_len = pack(blob, sizeof(blob), &p);
390 
391 	if (blob_len == 0 || blob_len > maxsize)
392 		return (0);
393 
394 	memcpy(data, blob, blob_len);
395 
396 	return (blob_len);
397 }
398