diff options
Diffstat (limited to 'fuzz/fuzz_cred.c')
-rw-r--r-- | fuzz/fuzz_cred.c | 458 |
1 files changed, 256 insertions, 202 deletions
diff --git a/fuzz/fuzz_cred.c b/fuzz/fuzz_cred.c index cc37903..87a877a 100644 --- a/fuzz/fuzz_cred.c +++ b/fuzz/fuzz_cred.c | |||
@@ -18,43 +18,25 @@ | |||
18 | 18 | ||
19 | #include "../openbsd-compat/openbsd-compat.h" | 19 | #include "../openbsd-compat/openbsd-compat.h" |
20 | 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. */ | 21 | /* Parameter set defining a FIDO2 make credential operation. */ |
40 | struct param { | 22 | struct param { |
41 | char pin[MAXSTR]; | 23 | char pin[MAXSTR]; |
42 | char rp_id[MAXSTR]; | 24 | char rp_id[MAXSTR]; |
43 | char rp_name[MAXSTR]; | 25 | char rp_name[MAXSTR]; |
44 | char user_icon[MAXSTR]; | 26 | char user_icon[MAXSTR]; |
45 | char user_name[MAXSTR]; | 27 | char user_name[MAXSTR]; |
46 | char user_nick[MAXSTR]; | 28 | char user_nick[MAXSTR]; |
47 | int ext; | 29 | int ext; |
48 | int seed; | 30 | int seed; |
49 | struct blob cdh; | 31 | struct blob cdh; |
50 | struct blob excl_cred; | 32 | struct blob excl_cred; |
51 | struct blob user_id; | 33 | struct blob user_id; |
52 | struct blob wire_data; | 34 | struct blob wire_data; |
53 | uint8_t excl_count; | 35 | uint8_t excl_count; |
54 | uint8_t rk; | 36 | uint8_t rk; |
55 | uint8_t type; | 37 | uint8_t type; |
56 | uint8_t u2f; | 38 | uint8_t u2f; |
57 | uint8_t uv; | 39 | uint8_t uv; |
58 | }; | 40 | }; |
59 | 41 | ||
60 | /* | 42 | /* |
@@ -86,79 +68,157 @@ static const uint8_t dummy_wire_data_u2f[] = { | |||
86 | WIREDATA_CTAP_U2F_REGISTER, | 68 | WIREDATA_CTAP_U2F_REGISTER, |
87 | }; | 69 | }; |
88 | 70 | ||
89 | int LLVMFuzzerTestOneInput(const uint8_t *, size_t); | 71 | struct param * |
90 | size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); | 72 | unpack(const uint8_t *ptr, size_t len) |
91 | |||
92 | static int | ||
93 | unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN | ||
94 | { | 73 | { |
95 | uint8_t **pp = (void *)&ptr; | 74 | cbor_item_t *item = NULL, **v; |
96 | 75 | struct cbor_load_result cbor; | |
97 | if (unpack_byte(TAG_RK, pp, &len, &p->rk) < 0 || | 76 | struct param *p; |
98 | unpack_byte(TAG_TYPE, pp, &len, &p->type) < 0 || | 77 | int ok = -1; |
99 | unpack_byte(TAG_U2F, pp, &len, &p->u2f) < 0 || | 78 | |
100 | unpack_byte(TAG_UV, pp, &len, &p->uv) < 0 || | 79 | if ((p = calloc(1, sizeof(*p))) == NULL || |
101 | unpack_byte(TAG_EXCL_COUNT, pp, &len, &p->excl_count) < 0 || | 80 | (item = cbor_load(ptr, len, &cbor)) == NULL || |
102 | unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || | 81 | cbor.read != len || |
103 | unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || | 82 | cbor_isa_array(item) == false || |
104 | unpack_string(TAG_RP_NAME, pp, &len, p->rp_name) < 0 || | 83 | cbor_array_is_definite(item) == false || |
105 | unpack_string(TAG_USER_ICON, pp, &len, p->user_icon) < 0 || | 84 | cbor_array_size(item) != 17 || |
106 | unpack_string(TAG_USER_NAME, pp, &len, p->user_name) < 0 || | 85 | (v = cbor_array_handle(item)) == NULL) |
107 | unpack_string(TAG_USER_NICK, pp, &len, p->user_nick) < 0 || | 86 | goto fail; |
108 | unpack_int(TAG_EXT, pp, &len, &p->ext) < 0 || | 87 | |
109 | unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || | 88 | if (unpack_byte(v[0], &p->rk) < 0 || |
110 | unpack_blob(TAG_CDH, pp, &len, &p->cdh) < 0 || | 89 | unpack_byte(v[1], &p->type) < 0 || |
111 | unpack_blob(TAG_USER_ID, pp, &len, &p->user_id) < 0 || | 90 | unpack_byte(v[2], &p->u2f) < 0 || |
112 | unpack_blob(TAG_WIRE_DATA, pp, &len, &p->wire_data) < 0 || | 91 | unpack_byte(v[3], &p->uv) < 0 || |
113 | unpack_blob(TAG_EXCL_CRED, pp, &len, &p->excl_cred) < 0) | 92 | unpack_byte(v[4], &p->excl_count) < 0 || |
114 | return (-1); | 93 | unpack_int(v[5], &p->ext) < 0 || |
115 | 94 | unpack_int(v[6], &p->seed) < 0 || | |
116 | return (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; | ||
117 | } | 118 | } |
118 | 119 | ||
119 | static size_t | 120 | size_t |
120 | pack(uint8_t *ptr, size_t len, const struct param *p) | 121 | pack(uint8_t *ptr, size_t len, const struct param *p) |
121 | { | 122 | { |
122 | const size_t max = len; | 123 | cbor_item_t *argv[17], *array = NULL; |
123 | 124 | size_t cbor_alloc_len, cbor_len = 0; | |
124 | if (pack_byte(TAG_RK, &ptr, &len, p->rk) < 0 || | 125 | unsigned char *cbor = NULL; |
125 | pack_byte(TAG_TYPE, &ptr, &len, p->type) < 0 || | 126 | |
126 | pack_byte(TAG_U2F, &ptr, &len, p->u2f) < 0 || | 127 | memset(argv, 0, sizeof(argv)); |
127 | pack_byte(TAG_UV, &ptr, &len, p->uv) < 0 || | 128 | |
128 | pack_byte(TAG_EXCL_COUNT, &ptr, &len, p->excl_count) < 0 || | 129 | if ((array = cbor_new_definite_array(17)) == NULL || |
129 | pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || | 130 | (argv[0] = pack_byte(p->rk)) == NULL || |
130 | pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || | 131 | (argv[1] = pack_byte(p->type)) == NULL || |
131 | pack_string(TAG_RP_NAME, &ptr, &len, p->rp_name) < 0 || | 132 | (argv[2] = pack_byte(p->u2f)) == NULL || |
132 | pack_string(TAG_USER_ICON, &ptr, &len, p->user_icon) < 0 || | 133 | (argv[3] = pack_byte(p->uv)) == NULL || |
133 | pack_string(TAG_USER_NAME, &ptr, &len, p->user_name) < 0 || | 134 | (argv[4] = pack_byte(p->excl_count)) == NULL || |
134 | pack_string(TAG_USER_NICK, &ptr, &len, p->user_nick) < 0 || | 135 | (argv[5] = pack_int(p->ext)) == NULL || |
135 | pack_int(TAG_EXT, &ptr, &len, p->ext) < 0 || | 136 | (argv[6] = pack_int(p->seed)) == NULL || |
136 | pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || | 137 | (argv[7] = pack_string(p->pin)) == NULL || |
137 | pack_blob(TAG_CDH, &ptr, &len, &p->cdh) < 0 || | 138 | (argv[8] = pack_string(p->rp_id)) == NULL || |
138 | pack_blob(TAG_USER_ID, &ptr, &len, &p->user_id) < 0 || | 139 | (argv[9] = pack_string(p->rp_name)) == NULL || |
139 | pack_blob(TAG_WIRE_DATA, &ptr, &len, &p->wire_data) < 0 || | 140 | (argv[10] = pack_string(p->user_icon)) == NULL || |
140 | pack_blob(TAG_EXCL_CRED, &ptr, &len, &p->excl_cred) < 0) | 141 | (argv[11] = pack_string(p->user_name)) == NULL || |
141 | return (0); | 142 | (argv[12] = pack_string(p->user_nick)) == NULL || |
142 | 143 | (argv[13] = pack_blob(&p->cdh)) == NULL || | |
143 | return (max - len); | 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; | ||
144 | } | 171 | } |
145 | 172 | ||
146 | static size_t | 173 | size_t |
147 | input_len(int max) | 174 | pack_dummy(uint8_t *ptr, size_t len) |
148 | { | 175 | { |
149 | return (5 * len_byte() + 6 * len_string(max) + 2 * len_int() + | 176 | struct param dummy; |
150 | 4 * len_blob(max)); | 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; | ||
151 | } | 211 | } |
152 | 212 | ||
153 | static void | 213 | static void |
154 | make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh, | 214 | 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, | 215 | const char *rp_id, const char *rp_name, const struct blob *user_id, |
156 | const char *user_name, const char *user_nick, const char *user_icon, | 216 | 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, | 217 | int ext, uint8_t rk, uint8_t uv, const char *pin, uint8_t excl_count, |
158 | struct blob *excl_cred) | 218 | const struct blob *excl_cred) |
159 | { | 219 | { |
160 | fido_dev_t *dev; | 220 | fido_dev_t *dev; |
161 | fido_dev_io_t io; | 221 | fido_dev_io_t io; |
162 | 222 | ||
163 | memset(&io, 0, sizeof(io)); | 223 | memset(&io, 0, sizeof(io)); |
164 | 224 | ||
@@ -185,6 +245,7 @@ make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh, | |||
185 | fido_cred_set_user(cred, user_id->body, user_id->len, user_name, | 245 | fido_cred_set_user(cred, user_id->body, user_id->len, user_name, |
186 | user_nick, user_icon); | 246 | user_nick, user_icon); |
187 | fido_cred_set_extensions(cred, ext); | 247 | fido_cred_set_extensions(cred, ext); |
248 | |||
188 | if (rk & 1) | 249 | if (rk & 1) |
189 | fido_cred_set_rk(cred, FIDO_OPT_TRUE); | 250 | fido_cred_set_rk(cred, FIDO_OPT_TRUE); |
190 | if (uv & 1) | 251 | if (uv & 1) |
@@ -192,6 +253,16 @@ make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh, | |||
192 | if (user_id->len) | 253 | if (user_id->len) |
193 | fido_cred_set_prot(cred, user_id->body[0] & 0x03); | 254 | fido_cred_set_prot(cred, user_id->body[0] & 0x03); |
194 | 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 | |||
195 | fido_dev_make_cred(dev, cred, u2f & 1 ? NULL : pin); | 266 | fido_dev_make_cred(dev, cred, u2f & 1 ? NULL : pin); |
196 | 267 | ||
197 | fido_dev_cancel(dev); | 268 | fido_dev_cancel(dev); |
@@ -206,8 +277,8 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len, | |||
206 | const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr, | 277 | const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr, |
207 | size_t sig_len, const char *fmt, int prot) | 278 | size_t sig_len, const char *fmt, int prot) |
208 | { | 279 | { |
209 | fido_cred_t *cred; | 280 | fido_cred_t *cred; |
210 | uint8_t flags; | 281 | uint8_t flags; |
211 | 282 | ||
212 | if ((cred = fido_cred_new()) == NULL) | 283 | if ((cred = fido_cred_new()) == NULL) |
213 | return; | 284 | return; |
@@ -229,11 +300,18 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len, | |||
229 | if (fmt) | 300 | if (fmt) |
230 | fido_cred_set_fmt(cred, fmt); | 301 | fido_cred_set_fmt(cred, fmt); |
231 | 302 | ||
232 | fido_cred_verify(cred); | 303 | /* repeat memory operations to trigger reallocation paths */ |
233 | fido_cred_verify_self(cred); | 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); | ||
234 | 311 | ||
235 | consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); | 312 | consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); |
236 | consume(fido_cred_id_ptr(cred), fido_cred_id_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)); | ||
237 | consume(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred)); | 315 | 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))); | 316 | consume(fido_cred_user_name(cred), xstrlen(fido_cred_user_name(cred))); |
239 | consume(fido_cred_display_name(cred), | 317 | consume(fido_cred_display_name(cred), |
@@ -247,30 +325,16 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len, | |||
247 | fido_cred_free(&cred); | 325 | fido_cred_free(&cred); |
248 | } | 326 | } |
249 | 327 | ||
250 | int | 328 | static void |
251 | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) | 329 | test_cred(const struct param *p) |
252 | { | 330 | { |
253 | struct param p; | 331 | fido_cred_t *cred = NULL; |
254 | fido_cred_t *cred = NULL; | 332 | int cose_alg = 0; |
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 | 333 | ||
268 | if ((cred = fido_cred_new()) == NULL) | 334 | if ((cred = fido_cred_new()) == NULL) |
269 | return (0); | 335 | return; |
270 | |||
271 | set_wire_data(p.wire_data.body, p.wire_data.len); | ||
272 | 336 | ||
273 | switch (p.type & 3) { | 337 | switch (p->type & 3) { |
274 | case 0: | 338 | case 0: |
275 | cose_alg = COSE_ES256; | 339 | cose_alg = COSE_ES256; |
276 | break; | 340 | break; |
@@ -282,116 +346,106 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) | |||
282 | break; | 346 | break; |
283 | } | 347 | } |
284 | 348 | ||
285 | make_cred(cred, p.u2f, cose_alg, &p.cdh, p.rp_id, p.rp_name, | 349 | set_wire_data(p->wire_data.body, p->wire_data.len); |
286 | &p.user_id, p.user_name, p.user_nick, p.user_icon, p.ext, p.rk, | 350 | |
287 | p.uv, p.pin, p.excl_count, &p.excl_cred); | 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); | ||
288 | 354 | ||
289 | verify_cred(cose_alg, | 355 | verify_cred(cose_alg, |
290 | fido_cred_clientdata_hash_ptr(cred), | 356 | fido_cred_clientdata_hash_ptr(cred), |
291 | fido_cred_clientdata_hash_len(cred), fido_cred_rp_id(cred), | 357 | fido_cred_clientdata_hash_len(cred), fido_cred_rp_id(cred), |
292 | fido_cred_rp_name(cred), fido_cred_authdata_ptr(cred), | 358 | fido_cred_rp_name(cred), fido_cred_authdata_ptr(cred), |
293 | fido_cred_authdata_len(cred), p.ext, p.rk, p.uv, | 359 | fido_cred_authdata_len(cred), p->ext, p->rk, p->uv, |
294 | fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred), | 360 | fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred), |
295 | fido_cred_sig_ptr(cred), fido_cred_sig_len(cred), | 361 | fido_cred_sig_ptr(cred), fido_cred_sig_len(cred), |
296 | fido_cred_fmt(cred), fido_cred_prot(cred)); | 362 | fido_cred_fmt(cred), fido_cred_prot(cred)); |
297 | 363 | ||
298 | fido_cred_free(&cred); | 364 | fido_cred_free(&cred); |
299 | |||
300 | return (0); | ||
301 | } | 365 | } |
302 | 366 | ||
303 | static size_t | 367 | static void |
304 | pack_dummy(uint8_t *ptr, size_t len) | 368 | test_touch(const struct param *p) |
305 | { | 369 | { |
306 | struct param dummy; | 370 | fido_dev_t *dev; |
307 | uint8_t blob[16384]; | 371 | fido_dev_io_t io; |
308 | size_t blob_len; | 372 | int r; |
373 | int touched; | ||
309 | 374 | ||
310 | memset(&dummy, 0, sizeof(dummy)); | 375 | memset(&io, 0, sizeof(io)); |
311 | 376 | ||
312 | dummy.type = 1; | 377 | io.open = dev_open; |
313 | dummy.ext = FIDO_EXT_HMAC_SECRET; | 378 | io.close = dev_close; |
379 | io.read = dev_read; | ||
380 | io.write = dev_write; | ||
314 | 381 | ||
315 | strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); | 382 | set_wire_data(p->wire_data.body, p->wire_data.len); |
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 | 383 | ||
322 | dummy.cdh.len = sizeof(dummy_cdh); | 384 | if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, |
323 | dummy.user_id.len = sizeof(dummy_user_id); | 385 | &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { |
324 | dummy.wire_data.len = sizeof(dummy_wire_data_fido); | 386 | fido_dev_free(&dev); |
387 | return; | ||
388 | } | ||
325 | 389 | ||
326 | memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); | 390 | if (p->u2f & 1) |
327 | memcpy(&dummy.user_id.body, &dummy_user_id, dummy.user_id.len); | 391 | fido_dev_force_u2f(dev); |
328 | memcpy(&dummy.wire_data.body, &dummy_wire_data_fido, | ||
329 | dummy.wire_data.len); | ||
330 | 392 | ||
331 | blob_len = pack(blob, sizeof(blob), &dummy); | 393 | r = fido_dev_get_touch_begin(dev); |
332 | assert(blob_len != 0); | 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)); | ||
333 | 398 | ||
334 | if (blob_len > len) { | 399 | fido_dev_cancel(dev); |
335 | memcpy(ptr, blob, len); | 400 | fido_dev_close(dev); |
336 | return (len); | 401 | fido_dev_free(&dev); |
337 | } | 402 | } |
338 | 403 | ||
339 | memcpy(ptr, blob, blob_len); | 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); | ||
340 | 410 | ||
341 | return (blob_len); | 411 | test_cred(p); |
412 | test_touch(p); | ||
342 | } | 413 | } |
343 | 414 | ||
344 | size_t | 415 | void |
345 | LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, | 416 | mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN |
346 | unsigned int seed) NO_MSAN | ||
347 | { | 417 | { |
348 | struct param p; | 418 | if (flags & MUTATE_SEED) |
349 | uint8_t blob[16384]; | 419 | p->seed = (int)seed; |
350 | size_t blob_len; | 420 | |
351 | 421 | if (flags & MUTATE_PARAM) { | |
352 | memset(&p, 0, sizeof(p)); | 422 | mutate_byte(&p->rk); |
353 | 423 | mutate_byte(&p->type); | |
354 | if (unpack(data, size, &p) < 0) | 424 | mutate_byte(&p->u2f); |
355 | return (pack_dummy(data, maxsize)); | 425 | mutate_byte(&p->uv); |
356 | 426 | mutate_byte(&p->excl_count); | |
357 | mutate_byte(&p.rk); | 427 | mutate_int(&p->ext); |
358 | mutate_byte(&p.type); | 428 | mutate_blob(&p->cdh); |
359 | mutate_byte(&p.u2f); | 429 | mutate_blob(&p->user_id); |
360 | mutate_byte(&p.uv); | 430 | mutate_blob(&p->excl_cred); |
361 | mutate_byte(&p.excl_count); | 431 | mutate_string(p->pin); |
362 | 432 | mutate_string(p->user_icon); | |
363 | mutate_int(&p.ext); | 433 | mutate_string(p->user_name); |
364 | p.seed = (int)seed; | 434 | mutate_string(p->user_nick); |
365 | 435 | mutate_string(p->rp_id); | |
366 | mutate_blob(&p.cdh); | 436 | mutate_string(p->rp_name); |
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 | } | 437 | } |
378 | 438 | ||
379 | mutate_blob(&p.wire_data); | 439 | if (flags & MUTATE_WIREDATA) { |
380 | mutate_blob(&p.excl_cred); | 440 | if (p->u2f & 1) { |
381 | 441 | p->wire_data.len = sizeof(dummy_wire_data_u2f); | |
382 | mutate_string(p.pin); | 442 | memcpy(&p->wire_data.body, &dummy_wire_data_u2f, |
383 | mutate_string(p.user_icon); | 443 | p->wire_data.len); |
384 | mutate_string(p.user_name); | 444 | } else { |
385 | mutate_string(p.user_nick); | 445 | p->wire_data.len = sizeof(dummy_wire_data_fido); |
386 | mutate_string(p.rp_id); | 446 | memcpy(&p->wire_data.body, &dummy_wire_data_fido, |
387 | mutate_string(p.rp_name); | 447 | p->wire_data.len); |
388 | 448 | } | |
389 | blob_len = pack(blob, sizeof(blob), &p); | 449 | mutate_blob(&p->wire_data); |
390 | 450 | } | |
391 | if (blob_len == 0 || blob_len > maxsize) | ||
392 | return (0); | ||
393 | |||
394 | memcpy(data, blob, blob_len); | ||
395 | |||
396 | return (blob_len); | ||
397 | } | 451 | } |