xref: /netbsd-src/external/bsd/libfido2/dist/fuzz/fuzz_credman.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 "dummy.h"
16 
17 #include "fido.h"
18 #include "fido/credman.h"
19 
20 #include "../openbsd-compat/openbsd-compat.h"
21 
22 #define TAG_META_WIRE_DATA	0x01
23 #define TAG_RP_WIRE_DATA	0x02
24 #define TAG_RK_WIRE_DATA	0x03
25 #define TAG_DEL_WIRE_DATA	0x04
26 #define TAG_CRED_ID		0x05
27 #define TAG_PIN			0x06
28 #define TAG_RP_ID		0x07
29 #define TAG_SEED		0x08
30 
31 /* Parameter set defining a FIDO2 credential management operation. */
32 struct param {
33 	char		pin[MAXSTR];
34 	char		rp_id[MAXSTR];
35 	int		seed;
36 	struct blob	cred_id;
37 	struct blob	del_wire_data;
38 	struct blob	meta_wire_data;
39 	struct blob	rk_wire_data;
40 	struct blob	rp_wire_data;
41 };
42 
43 /*
44  * Collection of HID reports from an authenticator issued with a FIDO2
45  * 'getCredsMetadata' credential management command.
46  */
47 static const uint8_t dummy_meta_wire_data[] = {
48 	WIREDATA_CTAP_INIT,
49 	WIREDATA_CTAP_CBOR_INFO,
50 	WIREDATA_CTAP_CBOR_AUTHKEY,
51 	WIREDATA_CTAP_CBOR_PINTOKEN,
52 	WIREDATA_CTAP_CBOR_CREDMAN_META,
53 };
54 
55 /*
56  * Collection of HID reports from an authenticator issued with a FIDO2
57  * 'enumerateRPsBegin' credential management command.
58  */
59 static const uint8_t dummy_rp_wire_data[] = {
60 	WIREDATA_CTAP_INIT,
61 	WIREDATA_CTAP_CBOR_INFO,
62 	WIREDATA_CTAP_CBOR_AUTHKEY,
63 	WIREDATA_CTAP_CBOR_PINTOKEN,
64 	WIREDATA_CTAP_CBOR_CREDMAN_RPLIST,
65 };
66 
67 /*
68  * Collection of HID reports from an authenticator issued with a FIDO2
69  * 'enumerateCredentialsBegin' credential management command.
70  */
71 static const uint8_t dummy_rk_wire_data[] = {
72 	WIREDATA_CTAP_INIT,
73 	WIREDATA_CTAP_CBOR_INFO,
74 	WIREDATA_CTAP_CBOR_AUTHKEY,
75 	WIREDATA_CTAP_CBOR_PINTOKEN,
76 	WIREDATA_CTAP_CBOR_CREDMAN_RKLIST,
77 };
78 
79 /*
80  * Collection of HID reports from an authenticator issued with a FIDO2
81  * 'deleteCredential' credential management command.
82  */
83 static const uint8_t dummy_del_wire_data[] = {
84 	WIREDATA_CTAP_INIT,
85 	WIREDATA_CTAP_CBOR_INFO,
86 	WIREDATA_CTAP_CBOR_AUTHKEY,
87 	WIREDATA_CTAP_CBOR_PINTOKEN,
88 	WIREDATA_CTAP_CBOR_STATUS,
89 };
90 
91 int    LLVMFuzzerTestOneInput(const uint8_t *, size_t);
92 size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int);
93 
94 static int
95 unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN
96 {
97 	uint8_t **pp = (void *)&ptr;
98 
99 	if (unpack_string(TAG_PIN, pp, &len, p->pin) < 0 ||
100 	    unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 ||
101 	    unpack_blob(TAG_CRED_ID, pp, &len, &p->cred_id) < 0 ||
102 	    unpack_blob(TAG_META_WIRE_DATA, pp, &len, &p->meta_wire_data) < 0 ||
103 	    unpack_blob(TAG_RP_WIRE_DATA, pp, &len, &p->rp_wire_data) < 0 ||
104 	    unpack_blob(TAG_RK_WIRE_DATA, pp, &len, &p->rk_wire_data) < 0 ||
105 	    unpack_blob(TAG_DEL_WIRE_DATA, pp, &len, &p->del_wire_data) < 0 ||
106 	    unpack_int(TAG_SEED, pp, &len, &p->seed) < 0)
107 		return (-1);
108 
109 	return (0);
110 }
111 
112 static size_t
113 pack(uint8_t *ptr, size_t len, const struct param *p)
114 {
115 	const size_t max = len;
116 
117 	if (pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 ||
118 	    pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 ||
119 	    pack_blob(TAG_CRED_ID, &ptr, &len, &p->cred_id) < 0 ||
120 	    pack_blob(TAG_META_WIRE_DATA, &ptr, &len, &p->meta_wire_data) < 0 ||
121 	    pack_blob(TAG_RP_WIRE_DATA, &ptr, &len, &p->rp_wire_data) < 0 ||
122 	    pack_blob(TAG_RK_WIRE_DATA, &ptr, &len, &p->rk_wire_data) < 0 ||
123 	    pack_blob(TAG_DEL_WIRE_DATA, &ptr, &len, &p->del_wire_data) < 0 ||
124 	    pack_int(TAG_SEED, &ptr, &len, p->seed) < 0)
125 		return (0);
126 
127 	return (max - len);
128 }
129 
130 static size_t
131 input_len(int max)
132 {
133 	return (2 * len_string(max) + 5 * len_blob(max) + len_int());
134 }
135 
136 static fido_dev_t *
137 prepare_dev()
138 {
139 	fido_dev_t	*dev;
140 	fido_dev_io_t	 io;
141 
142 	memset(&io, 0, sizeof(io));
143 
144 	io.open = dev_open;
145 	io.close = dev_close;
146 	io.read = dev_read;
147 	io.write = dev_write;
148 
149 	if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
150 	    &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
151 		fido_dev_free(&dev);
152 		return (NULL);
153 	}
154 
155 	return (dev);
156 }
157 
158 static void
159 get_metadata(struct param *p)
160 {
161 	fido_dev_t *dev;
162 	fido_credman_metadata_t *metadata;
163 	uint64_t existing;
164 	uint64_t remaining;
165 
166 	set_wire_data(p->meta_wire_data.body, p->meta_wire_data.len);
167 
168 	if ((dev = prepare_dev()) == NULL)
169 		return;
170 
171 	if ((metadata = fido_credman_metadata_new()) == NULL) {
172 		fido_dev_close(dev);
173 		fido_dev_free(&dev);
174 		return;
175 	}
176 
177 	fido_credman_get_dev_metadata(dev, metadata, p->pin);
178 
179 	existing = fido_credman_rk_existing(metadata);
180 	remaining = fido_credman_rk_remaining(metadata);
181 	consume(&existing, sizeof(existing));
182 	consume(&remaining, sizeof(remaining));
183 
184 	fido_credman_metadata_free(&metadata);
185 	fido_dev_close(dev);
186 	fido_dev_free(&dev);
187 }
188 
189 static void
190 get_rp_list(struct param *p)
191 {
192 	fido_dev_t *dev;
193 	fido_credman_rp_t *rp;
194 
195 	set_wire_data(p->rp_wire_data.body, p->rp_wire_data.len);
196 
197 	if ((dev = prepare_dev()) == NULL)
198 		return;
199 
200 	if ((rp = fido_credman_rp_new()) == NULL) {
201 		fido_dev_close(dev);
202 		fido_dev_free(&dev);
203 		return;
204 	}
205 
206 	fido_credman_get_dev_rp(dev, rp, p->pin);
207 
208 	/* +1 on purpose */
209 	for (size_t i = 0; i < fido_credman_rp_count(rp) + 1; i++) {
210 		consume(fido_credman_rp_id_hash_ptr(rp, i),
211 		    fido_credman_rp_id_hash_len(rp, i));
212 		consume(fido_credman_rp_id(rp, i),
213 		    xstrlen(fido_credman_rp_id(rp, i)));
214 		consume(fido_credman_rp_name(rp, i),
215 		    xstrlen(fido_credman_rp_name(rp, i)));
216 	}
217 
218 	fido_credman_rp_free(&rp);
219 	fido_dev_close(dev);
220 	fido_dev_free(&dev);
221 }
222 
223 static void
224 get_rk_list(struct param *p)
225 {
226 	fido_dev_t *dev;
227 	fido_credman_rk_t *rk;
228 	const fido_cred_t *cred;
229 	int type;
230 
231 	set_wire_data(p->rk_wire_data.body, p->rk_wire_data.len);
232 
233 	if ((dev = prepare_dev()) == NULL)
234 		return;
235 
236 	if ((rk = fido_credman_rk_new()) == NULL) {
237 		fido_dev_close(dev);
238 		fido_dev_free(&dev);
239 		return;
240 	}
241 
242 	fido_credman_get_dev_rk(dev, p->rp_id, rk, p->pin);
243 
244 	/* +1 on purpose */
245 	for (size_t i = 0; i < fido_credman_rk_count(rk) + 1; i++) {
246 		if ((cred = fido_credman_rk(rk, i)) == NULL) {
247 			assert(i >= fido_credman_rk_count(rk));
248 			continue;
249 		}
250 		type = fido_cred_type(cred);
251 		consume(&type, sizeof(type));
252 		consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred));
253 		consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred));
254 		consume(fido_cred_user_id_ptr(cred),
255 		    fido_cred_user_id_len(cred));
256 		consume(fido_cred_user_name(cred),
257 		    xstrlen(fido_cred_user_name(cred)));
258 		consume(fido_cred_display_name(cred),
259 		    xstrlen(fido_cred_display_name(cred)));
260 	}
261 
262 	fido_credman_rk_free(&rk);
263 	fido_dev_close(dev);
264 	fido_dev_free(&dev);
265 }
266 
267 static void
268 del_rk(struct param *p)
269 {
270 	fido_dev_t *dev;
271 
272 	set_wire_data(p->del_wire_data.body, p->del_wire_data.len);
273 
274 	if ((dev = prepare_dev()) == NULL)
275 		return;
276 
277 	fido_credman_del_dev_rk(dev, p->cred_id.body, p->cred_id.len, p->pin);
278 	fido_dev_close(dev);
279 	fido_dev_free(&dev);
280 }
281 
282 int
283 LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
284 {
285 	struct param p;
286 
287 	memset(&p, 0, sizeof(p));
288 
289 	if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) ||
290 	    unpack(data, size, &p) < 0)
291 		return (0);
292 
293 	prng_init((unsigned int)p.seed);
294 
295 	fido_init(FIDO_DEBUG);
296 	fido_set_log_handler(consume_str);
297 
298 	get_metadata(&p);
299 	get_rp_list(&p);
300 	get_rk_list(&p);
301 	del_rk(&p);
302 
303 	return (0);
304 }
305 
306 static size_t
307 pack_dummy(uint8_t *ptr, size_t len)
308 {
309 	struct param	dummy;
310 	uint8_t		blob[32768];
311 	size_t		blob_len;
312 
313 	memset(&dummy, 0, sizeof(dummy));
314 
315 	strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
316 	strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id));
317 
318 	dummy.meta_wire_data.len = sizeof(dummy_meta_wire_data);
319 	dummy.rp_wire_data.len = sizeof(dummy_rp_wire_data);
320 	dummy.rk_wire_data.len = sizeof(dummy_rk_wire_data);
321 	dummy.del_wire_data.len = sizeof(dummy_del_wire_data);
322 	dummy.cred_id.len = sizeof(dummy_cred_id);
323 
324 	memcpy(&dummy.meta_wire_data.body, &dummy_meta_wire_data,
325 	    dummy.meta_wire_data.len);
326 	memcpy(&dummy.rp_wire_data.body, &dummy_rp_wire_data,
327 	    dummy.rp_wire_data.len);
328 	memcpy(&dummy.rk_wire_data.body, &dummy_rk_wire_data,
329 	    dummy.rk_wire_data.len);
330 	memcpy(&dummy.del_wire_data.body, &dummy_del_wire_data,
331 	    dummy.del_wire_data.len);
332 	memcpy(&dummy.cred_id.body, &dummy_cred_id, dummy.cred_id.len);
333 
334 	blob_len = pack(blob, sizeof(blob), &dummy);
335 	assert(blob_len != 0);
336 
337 	if (blob_len > len) {
338 		memcpy(ptr, blob, len);
339 		return (len);
340 	}
341 
342 	memcpy(ptr, blob, blob_len);
343 
344 	return (blob_len);
345 }
346 
347 size_t
348 LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize,
349     unsigned int seed) NO_MSAN
350 {
351 	struct param	p;
352 	uint8_t		blob[16384];
353 	size_t		blob_len;
354 
355 	memset(&p, 0, sizeof(p));
356 
357 	if (unpack(data, size, &p) < 0)
358 		return (pack_dummy(data, maxsize));
359 
360 	p.seed = (int)seed;
361 
362 	mutate_blob(&p.cred_id);
363 	mutate_blob(&p.meta_wire_data);
364 	mutate_blob(&p.rp_wire_data);
365 	mutate_blob(&p.rk_wire_data);
366 	mutate_blob(&p.del_wire_data);
367 
368 	mutate_string(p.pin);
369 	mutate_string(p.rp_id);
370 
371 	blob_len = pack(blob, sizeof(blob), &p);
372 
373 	if (blob_len == 0 || blob_len > maxsize)
374 		return (0);
375 
376 	memcpy(data, blob, blob_len);
377 
378 	return (blob_len);
379 }
380