diff options
author | Colin Watson <cjwatson@debian.org> | 2020-09-20 16:14:20 +0100 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2020-09-20 16:14:20 +0100 |
commit | 173bfbf7886608a4a7abbfac6a42ac4bf4a3432d (patch) | |
tree | b97833d8754f257f92d99dd2f5c9e9d557e3f689 /fuzz/fuzz_credman.c | |
parent | 75073d0a8478441cc97a6efa10b566c5fb1dac81 (diff) |
New upstream version 1.5.0
Diffstat (limited to 'fuzz/fuzz_credman.c')
-rw-r--r-- | fuzz/fuzz_credman.c | 314 |
1 files changed, 163 insertions, 151 deletions
diff --git a/fuzz/fuzz_credman.c b/fuzz/fuzz_credman.c index 323d0a9..db0dfb8 100644 --- a/fuzz/fuzz_credman.c +++ b/fuzz/fuzz_credman.c | |||
@@ -19,25 +19,16 @@ | |||
19 | 19 | ||
20 | #include "../openbsd-compat/openbsd-compat.h" | 20 | #include "../openbsd-compat/openbsd-compat.h" |
21 | 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. */ | 22 | /* Parameter set defining a FIDO2 credential management operation. */ |
32 | struct param { | 23 | struct param { |
33 | char pin[MAXSTR]; | 24 | char pin[MAXSTR]; |
34 | char rp_id[MAXSTR]; | 25 | char rp_id[MAXSTR]; |
35 | int seed; | 26 | int seed; |
36 | struct blob cred_id; | 27 | struct blob cred_id; |
37 | struct blob del_wire_data; | 28 | struct blob del_wire_data; |
38 | struct blob meta_wire_data; | 29 | struct blob meta_wire_data; |
39 | struct blob rk_wire_data; | 30 | struct blob rk_wire_data; |
40 | struct blob rp_wire_data; | 31 | struct blob rp_wire_data; |
41 | }; | 32 | }; |
42 | 33 | ||
43 | /* | 34 | /* |
@@ -88,56 +79,136 @@ static const uint8_t dummy_del_wire_data[] = { | |||
88 | WIREDATA_CTAP_CBOR_STATUS, | 79 | WIREDATA_CTAP_CBOR_STATUS, |
89 | }; | 80 | }; |
90 | 81 | ||
91 | int LLVMFuzzerTestOneInput(const uint8_t *, size_t); | 82 | struct param * |
92 | size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); | 83 | unpack(const uint8_t *ptr, size_t len) |
93 | |||
94 | static int | ||
95 | unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN | ||
96 | { | 84 | { |
97 | uint8_t **pp = (void *)&ptr; | 85 | cbor_item_t *item = NULL, **v; |
98 | 86 | struct cbor_load_result cbor; | |
99 | if (unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || | 87 | struct param *p; |
100 | unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || | 88 | int ok = -1; |
101 | unpack_blob(TAG_CRED_ID, pp, &len, &p->cred_id) < 0 || | 89 | |
102 | unpack_blob(TAG_META_WIRE_DATA, pp, &len, &p->meta_wire_data) < 0 || | 90 | if ((p = calloc(1, sizeof(*p))) == NULL || |
103 | unpack_blob(TAG_RP_WIRE_DATA, pp, &len, &p->rp_wire_data) < 0 || | 91 | (item = cbor_load(ptr, len, &cbor)) == NULL || |
104 | unpack_blob(TAG_RK_WIRE_DATA, pp, &len, &p->rk_wire_data) < 0 || | 92 | cbor.read != len || |
105 | unpack_blob(TAG_DEL_WIRE_DATA, pp, &len, &p->del_wire_data) < 0 || | 93 | cbor_isa_array(item) == false || |
106 | unpack_int(TAG_SEED, pp, &len, &p->seed) < 0) | 94 | cbor_array_is_definite(item) == false || |
107 | return (-1); | 95 | cbor_array_size(item) != 8 || |
108 | 96 | (v = cbor_array_handle(item)) == NULL) | |
109 | return (0); | 97 | goto fail; |
98 | |||
99 | if (unpack_int(v[0], &p->seed) < 0 || | ||
100 | unpack_string(v[1], p->pin) < 0 || | ||
101 | unpack_string(v[2], p->rp_id) < 0 || | ||
102 | unpack_blob(v[3], &p->cred_id) < 0 || | ||
103 | unpack_blob(v[4], &p->meta_wire_data) < 0 || | ||
104 | unpack_blob(v[5], &p->rp_wire_data) < 0 || | ||
105 | unpack_blob(v[6], &p->rk_wire_data) < 0 || | ||
106 | unpack_blob(v[7], &p->del_wire_data) < 0) | ||
107 | goto fail; | ||
108 | |||
109 | ok = 0; | ||
110 | fail: | ||
111 | if (ok < 0) { | ||
112 | free(p); | ||
113 | p = NULL; | ||
114 | } | ||
115 | |||
116 | if (item) | ||
117 | cbor_decref(&item); | ||
118 | |||
119 | return p; | ||
110 | } | 120 | } |
111 | 121 | ||
112 | static size_t | 122 | size_t |
113 | pack(uint8_t *ptr, size_t len, const struct param *p) | 123 | pack(uint8_t *ptr, size_t len, const struct param *p) |
114 | { | 124 | { |
115 | const size_t max = len; | 125 | cbor_item_t *argv[8], *array = NULL; |
116 | 126 | size_t cbor_alloc_len, cbor_len = 0; | |
117 | if (pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || | 127 | unsigned char *cbor = NULL; |
118 | pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || | 128 | |
119 | pack_blob(TAG_CRED_ID, &ptr, &len, &p->cred_id) < 0 || | 129 | memset(argv, 0, sizeof(argv)); |
120 | pack_blob(TAG_META_WIRE_DATA, &ptr, &len, &p->meta_wire_data) < 0 || | 130 | |
121 | pack_blob(TAG_RP_WIRE_DATA, &ptr, &len, &p->rp_wire_data) < 0 || | 131 | if ((array = cbor_new_definite_array(8)) == NULL || |
122 | pack_blob(TAG_RK_WIRE_DATA, &ptr, &len, &p->rk_wire_data) < 0 || | 132 | (argv[0] = pack_int(p->seed)) == NULL || |
123 | pack_blob(TAG_DEL_WIRE_DATA, &ptr, &len, &p->del_wire_data) < 0 || | 133 | (argv[1] = pack_string(p->pin)) == NULL || |
124 | pack_int(TAG_SEED, &ptr, &len, p->seed) < 0) | 134 | (argv[2] = pack_string(p->rp_id)) == NULL || |
125 | return (0); | 135 | (argv[3] = pack_blob(&p->cred_id)) == NULL || |
126 | 136 | (argv[4] = pack_blob(&p->meta_wire_data)) == NULL || | |
127 | return (max - len); | 137 | (argv[5] = pack_blob(&p->rp_wire_data)) == NULL || |
138 | (argv[6] = pack_blob(&p->rk_wire_data)) == NULL || | ||
139 | (argv[7] = pack_blob(&p->del_wire_data)) == NULL) | ||
140 | goto fail; | ||
141 | |||
142 | for (size_t i = 0; i < 8; i++) | ||
143 | if (cbor_array_push(array, argv[i]) == false) | ||
144 | goto fail; | ||
145 | |||
146 | if ((cbor_len = cbor_serialize_alloc(array, &cbor, | ||
147 | &cbor_alloc_len)) > len) { | ||
148 | cbor_len = 0; | ||
149 | goto fail; | ||
150 | } | ||
151 | |||
152 | memcpy(ptr, cbor, cbor_len); | ||
153 | fail: | ||
154 | for (size_t i = 0; i < 8; i++) | ||
155 | if (argv[i]) | ||
156 | cbor_decref(&argv[i]); | ||
157 | |||
158 | if (array) | ||
159 | cbor_decref(&array); | ||
160 | |||
161 | free(cbor); | ||
162 | |||
163 | return cbor_len; | ||
128 | } | 164 | } |
129 | 165 | ||
130 | static size_t | 166 | size_t |
131 | input_len(int max) | 167 | pack_dummy(uint8_t *ptr, size_t len) |
132 | { | 168 | { |
133 | return (2 * len_string(max) + 5 * len_blob(max) + len_int()); | 169 | struct param dummy; |
170 | uint8_t blob[4096]; | ||
171 | size_t blob_len; | ||
172 | |||
173 | memset(&dummy, 0, sizeof(dummy)); | ||
174 | |||
175 | strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); | ||
176 | strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); | ||
177 | |||
178 | dummy.meta_wire_data.len = sizeof(dummy_meta_wire_data); | ||
179 | dummy.rp_wire_data.len = sizeof(dummy_rp_wire_data); | ||
180 | dummy.rk_wire_data.len = sizeof(dummy_rk_wire_data); | ||
181 | dummy.del_wire_data.len = sizeof(dummy_del_wire_data); | ||
182 | dummy.cred_id.len = sizeof(dummy_cred_id); | ||
183 | |||
184 | memcpy(&dummy.meta_wire_data.body, &dummy_meta_wire_data, | ||
185 | dummy.meta_wire_data.len); | ||
186 | memcpy(&dummy.rp_wire_data.body, &dummy_rp_wire_data, | ||
187 | dummy.rp_wire_data.len); | ||
188 | memcpy(&dummy.rk_wire_data.body, &dummy_rk_wire_data, | ||
189 | dummy.rk_wire_data.len); | ||
190 | memcpy(&dummy.del_wire_data.body, &dummy_del_wire_data, | ||
191 | dummy.del_wire_data.len); | ||
192 | memcpy(&dummy.cred_id.body, &dummy_cred_id, dummy.cred_id.len); | ||
193 | |||
194 | assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); | ||
195 | |||
196 | if (blob_len > len) { | ||
197 | memcpy(ptr, blob, len); | ||
198 | return len; | ||
199 | } | ||
200 | |||
201 | memcpy(ptr, blob, blob_len); | ||
202 | |||
203 | return blob_len; | ||
134 | } | 204 | } |
135 | 205 | ||
136 | static fido_dev_t * | 206 | static fido_dev_t * |
137 | prepare_dev() | 207 | prepare_dev(void) |
138 | { | 208 | { |
139 | fido_dev_t *dev; | 209 | fido_dev_t *dev; |
140 | fido_dev_io_t io; | 210 | fido_dev_io_t io; |
211 | bool x; | ||
141 | 212 | ||
142 | memset(&io, 0, sizeof(io)); | 213 | memset(&io, 0, sizeof(io)); |
143 | 214 | ||
@@ -149,14 +220,19 @@ prepare_dev() | |||
149 | if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, | 220 | if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, |
150 | &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { | 221 | &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { |
151 | fido_dev_free(&dev); | 222 | fido_dev_free(&dev); |
152 | return (NULL); | 223 | return NULL; |
153 | } | 224 | } |
154 | 225 | ||
155 | return (dev); | 226 | x = fido_dev_is_fido2(dev); |
227 | consume(&x, sizeof(x)); | ||
228 | x = fido_dev_supports_cred_prot(dev); | ||
229 | consume(&x, sizeof(x)); | ||
230 | |||
231 | return dev; | ||
156 | } | 232 | } |
157 | 233 | ||
158 | static void | 234 | static void |
159 | get_metadata(struct param *p) | 235 | get_metadata(const struct param *p) |
160 | { | 236 | { |
161 | fido_dev_t *dev; | 237 | fido_dev_t *dev; |
162 | fido_credman_metadata_t *metadata; | 238 | fido_credman_metadata_t *metadata; |
@@ -187,7 +263,7 @@ get_metadata(struct param *p) | |||
187 | } | 263 | } |
188 | 264 | ||
189 | static void | 265 | static void |
190 | get_rp_list(struct param *p) | 266 | get_rp_list(const struct param *p) |
191 | { | 267 | { |
192 | fido_dev_t *dev; | 268 | fido_dev_t *dev; |
193 | fido_credman_rp_t *rp; | 269 | fido_credman_rp_t *rp; |
@@ -221,12 +297,12 @@ get_rp_list(struct param *p) | |||
221 | } | 297 | } |
222 | 298 | ||
223 | static void | 299 | static void |
224 | get_rk_list(struct param *p) | 300 | get_rk_list(const struct param *p) |
225 | { | 301 | { |
226 | fido_dev_t *dev; | 302 | fido_dev_t *dev; |
227 | fido_credman_rk_t *rk; | 303 | fido_credman_rk_t *rk; |
228 | const fido_cred_t *cred; | 304 | const fido_cred_t *cred; |
229 | int type; | 305 | int val; |
230 | 306 | ||
231 | set_wire_data(p->rk_wire_data.body, p->rk_wire_data.len); | 307 | set_wire_data(p->rk_wire_data.body, p->rk_wire_data.len); |
232 | 308 | ||
@@ -247,8 +323,8 @@ get_rk_list(struct param *p) | |||
247 | assert(i >= fido_credman_rk_count(rk)); | 323 | assert(i >= fido_credman_rk_count(rk)); |
248 | continue; | 324 | continue; |
249 | } | 325 | } |
250 | type = fido_cred_type(cred); | 326 | val = fido_cred_type(cred); |
251 | consume(&type, sizeof(type)); | 327 | consume(&val, sizeof(val)); |
252 | consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); | 328 | consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); |
253 | consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); | 329 | consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); |
254 | consume(fido_cred_user_id_ptr(cred), | 330 | consume(fido_cred_user_id_ptr(cred), |
@@ -257,6 +333,8 @@ get_rk_list(struct param *p) | |||
257 | xstrlen(fido_cred_user_name(cred))); | 333 | xstrlen(fido_cred_user_name(cred))); |
258 | consume(fido_cred_display_name(cred), | 334 | consume(fido_cred_display_name(cred), |
259 | xstrlen(fido_cred_display_name(cred))); | 335 | xstrlen(fido_cred_display_name(cred))); |
336 | val = fido_cred_prot(cred); | ||
337 | consume(&val, sizeof(val)); | ||
260 | } | 338 | } |
261 | 339 | ||
262 | fido_credman_rk_free(&rk); | 340 | fido_credman_rk_free(&rk); |
@@ -265,7 +343,7 @@ get_rk_list(struct param *p) | |||
265 | } | 343 | } |
266 | 344 | ||
267 | static void | 345 | static void |
268 | del_rk(struct param *p) | 346 | del_rk(const struct param *p) |
269 | { | 347 | { |
270 | fido_dev_t *dev; | 348 | fido_dev_t *dev; |
271 | 349 | ||
@@ -279,101 +357,35 @@ del_rk(struct param *p) | |||
279 | fido_dev_free(&dev); | 357 | fido_dev_free(&dev); |
280 | } | 358 | } |
281 | 359 | ||
282 | int | 360 | void |
283 | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) | 361 | test(const struct param *p) |
284 | { | 362 | { |
285 | struct param p; | 363 | prng_init((unsigned int)p->seed); |
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); | 364 | fido_init(FIDO_DEBUG); |
296 | fido_set_log_handler(consume_str); | 365 | fido_set_log_handler(consume_str); |
297 | 366 | ||
298 | get_metadata(&p); | 367 | get_metadata(p); |
299 | get_rp_list(&p); | 368 | get_rp_list(p); |
300 | get_rk_list(&p); | 369 | get_rk_list(p); |
301 | del_rk(&p); | 370 | del_rk(p); |
302 | |||
303 | return (0); | ||
304 | } | 371 | } |
305 | 372 | ||
306 | static size_t | 373 | void |
307 | pack_dummy(uint8_t *ptr, size_t len) | 374 | mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN |
308 | { | 375 | { |
309 | struct param dummy; | 376 | if (flags & MUTATE_SEED) |
310 | uint8_t blob[32768]; | 377 | p->seed = (int)seed; |
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 | 378 | ||
318 | dummy.meta_wire_data.len = sizeof(dummy_meta_wire_data); | 379 | if (flags & MUTATE_PARAM) { |
319 | dummy.rp_wire_data.len = sizeof(dummy_rp_wire_data); | 380 | mutate_blob(&p->cred_id); |
320 | dummy.rk_wire_data.len = sizeof(dummy_rk_wire_data); | 381 | mutate_string(p->pin); |
321 | dummy.del_wire_data.len = sizeof(dummy_del_wire_data); | 382 | mutate_string(p->rp_id); |
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 | } | 383 | } |
341 | 384 | ||
342 | memcpy(ptr, blob, blob_len); | 385 | if (flags & MUTATE_WIREDATA) { |
343 | 386 | mutate_blob(&p->meta_wire_data); | |
344 | return (blob_len); | 387 | mutate_blob(&p->rp_wire_data); |
345 | } | 388 | mutate_blob(&p->rk_wire_data); |
346 | 389 | mutate_blob(&p->del_wire_data); | |
347 | size_t | 390 | } |
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 | } | 391 | } |