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 <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 13 #include "mutator_aux.h" 14 #include "wiredata_fido2.h" 15 #include "dummy.h" 16 17 #include "../openbsd-compat/openbsd-compat.h" 18 19 #define MAXRPID 64 20 21 struct param { 22 char pin1[MAXSTR]; 23 char pin2[MAXSTR]; 24 struct blob reset_wire_data; 25 struct blob info_wire_data; 26 struct blob set_pin_wire_data; 27 struct blob change_pin_wire_data; 28 struct blob retry_wire_data; 29 struct blob config_wire_data; 30 int seed; 31 }; 32 33 static const uint8_t dummy_reset_wire_data[] = { 34 WIREDATA_CTAP_INIT, 35 WIREDATA_CTAP_CBOR_INFO, 36 WIREDATA_CTAP_KEEPALIVE, 37 WIREDATA_CTAP_KEEPALIVE, 38 WIREDATA_CTAP_KEEPALIVE, 39 WIREDATA_CTAP_CBOR_STATUS, 40 }; 41 42 static const uint8_t dummy_info_wire_data[] = { 43 WIREDATA_CTAP_INIT, 44 WIREDATA_CTAP_CBOR_INFO, 45 WIREDATA_CTAP_CBOR_INFO, 46 }; 47 48 static const uint8_t dummy_set_pin_wire_data[] = { 49 WIREDATA_CTAP_INIT, 50 WIREDATA_CTAP_CBOR_INFO, 51 WIREDATA_CTAP_CBOR_AUTHKEY, 52 WIREDATA_CTAP_CBOR_STATUS, 53 }; 54 55 static const uint8_t dummy_change_pin_wire_data[] = { 56 WIREDATA_CTAP_INIT, 57 WIREDATA_CTAP_CBOR_INFO, 58 WIREDATA_CTAP_CBOR_AUTHKEY, 59 WIREDATA_CTAP_CBOR_STATUS, 60 }; 61 62 static const uint8_t dummy_retry_wire_data[] = { 63 WIREDATA_CTAP_INIT, 64 WIREDATA_CTAP_CBOR_INFO, 65 WIREDATA_CTAP_CBOR_RETRIES, 66 }; 67 68 static const uint8_t dummy_config_wire_data[] = { 69 WIREDATA_CTAP_INIT, 70 WIREDATA_CTAP_CBOR_INFO, 71 WIREDATA_CTAP_CBOR_STATUS, 72 }; 73 74 struct param * 75 unpack(const uint8_t *ptr, size_t len) 76 { 77 cbor_item_t *item = NULL, **v; 78 struct cbor_load_result cbor; 79 struct param *p; 80 int ok = -1; 81 82 if ((p = calloc(1, sizeof(*p))) == NULL || 83 (item = cbor_load(ptr, len, &cbor)) == NULL || 84 cbor.read != len || 85 cbor_isa_array(item) == false || 86 cbor_array_is_definite(item) == false || 87 cbor_array_size(item) != 9 || 88 (v = cbor_array_handle(item)) == NULL) 89 goto fail; 90 91 if (unpack_int(v[0], &p->seed) < 0 || 92 unpack_string(v[1], p->pin1) < 0 || 93 unpack_string(v[2], p->pin2) < 0 || 94 unpack_blob(v[3], &p->reset_wire_data) < 0 || 95 unpack_blob(v[4], &p->info_wire_data) < 0 || 96 unpack_blob(v[5], &p->set_pin_wire_data) < 0 || 97 unpack_blob(v[6], &p->change_pin_wire_data) < 0 || 98 unpack_blob(v[7], &p->retry_wire_data) < 0 || 99 unpack_blob(v[8], &p->config_wire_data) < 0) 100 goto fail; 101 102 ok = 0; 103 fail: 104 if (ok < 0) { 105 free(p); 106 p = NULL; 107 } 108 109 if (item) 110 cbor_decref(&item); 111 112 return p; 113 } 114 115 size_t 116 pack(uint8_t *ptr, size_t len, const struct param *p) 117 { 118 cbor_item_t *argv[9], *array = NULL; 119 size_t cbor_alloc_len, cbor_len = 0; 120 unsigned char *cbor = NULL; 121 122 memset(argv, 0, sizeof(argv)); 123 124 if ((array = cbor_new_definite_array(9)) == NULL || 125 (argv[0] = pack_int(p->seed)) == NULL || 126 (argv[1] = pack_string(p->pin1)) == NULL || 127 (argv[2] = pack_string(p->pin2)) == NULL || 128 (argv[3] = pack_blob(&p->reset_wire_data)) == NULL || 129 (argv[4] = pack_blob(&p->info_wire_data)) == NULL || 130 (argv[5] = pack_blob(&p->set_pin_wire_data)) == NULL || 131 (argv[6] = pack_blob(&p->change_pin_wire_data)) == NULL || 132 (argv[7] = pack_blob(&p->retry_wire_data)) == NULL || 133 (argv[8] = pack_blob(&p->config_wire_data)) == NULL) 134 goto fail; 135 136 for (size_t i = 0; i < 9; i++) 137 if (cbor_array_push(array, argv[i]) == false) 138 goto fail; 139 140 if ((cbor_len = cbor_serialize_alloc(array, &cbor, 141 &cbor_alloc_len)) > len) { 142 cbor_len = 0; 143 goto fail; 144 } 145 146 memcpy(ptr, cbor, cbor_len); 147 fail: 148 for (size_t i = 0; i < 9; i++) 149 if (argv[i]) 150 cbor_decref(&argv[i]); 151 152 if (array) 153 cbor_decref(&array); 154 155 free(cbor); 156 157 return cbor_len; 158 } 159 160 size_t 161 pack_dummy(uint8_t *ptr, size_t len) 162 { 163 struct param dummy; 164 uint8_t blob[4096]; 165 size_t blob_len; 166 167 memset(&dummy, 0, sizeof(dummy)); 168 169 strlcpy(dummy.pin1, dummy_pin1, sizeof(dummy.pin1)); 170 strlcpy(dummy.pin2, dummy_pin2, sizeof(dummy.pin2)); 171 172 dummy.reset_wire_data.len = sizeof(dummy_reset_wire_data); 173 dummy.info_wire_data.len = sizeof(dummy_info_wire_data); 174 dummy.set_pin_wire_data.len = sizeof(dummy_set_pin_wire_data); 175 dummy.change_pin_wire_data.len = sizeof(dummy_change_pin_wire_data); 176 dummy.retry_wire_data.len = sizeof(dummy_retry_wire_data); 177 dummy.config_wire_data.len = sizeof(dummy_config_wire_data); 178 179 memcpy(&dummy.reset_wire_data.body, &dummy_reset_wire_data, 180 dummy.reset_wire_data.len); 181 memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data, 182 dummy.info_wire_data.len); 183 memcpy(&dummy.set_pin_wire_data.body, &dummy_set_pin_wire_data, 184 dummy.set_pin_wire_data.len); 185 memcpy(&dummy.change_pin_wire_data.body, &dummy_change_pin_wire_data, 186 dummy.change_pin_wire_data.len); 187 memcpy(&dummy.retry_wire_data.body, &dummy_retry_wire_data, 188 dummy.retry_wire_data.len); 189 memcpy(&dummy.config_wire_data.body, &dummy_config_wire_data, 190 dummy.config_wire_data.len); 191 192 assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); 193 194 if (blob_len > len) { 195 memcpy(ptr, blob, len); 196 return len; 197 } 198 199 memcpy(ptr, blob, blob_len); 200 201 return blob_len; 202 } 203 204 static void 205 dev_reset(const struct param *p) 206 { 207 fido_dev_t *dev; 208 209 set_wire_data(p->reset_wire_data.body, p->reset_wire_data.len); 210 211 if ((dev = open_dev(0)) == NULL) 212 return; 213 214 fido_dev_reset(dev); 215 fido_dev_close(dev); 216 fido_dev_free(&dev); 217 } 218 219 static void 220 dev_get_cbor_info(const struct param *p) 221 { 222 fido_dev_t *dev; 223 fido_cbor_info_t *ci; 224 uint64_t n; 225 uint8_t proto, major, minor, build, flags; 226 227 set_wire_data(p->info_wire_data.body, p->info_wire_data.len); 228 229 if ((dev = open_dev(0)) == NULL) 230 return; 231 232 proto = fido_dev_protocol(dev); 233 major = fido_dev_major(dev); 234 minor = fido_dev_minor(dev); 235 build = fido_dev_build(dev); 236 flags = fido_dev_flags(dev); 237 238 consume(&proto, sizeof(proto)); 239 consume(&major, sizeof(major)); 240 consume(&minor, sizeof(minor)); 241 consume(&build, sizeof(build)); 242 consume(&flags, sizeof(flags)); 243 244 if ((ci = fido_cbor_info_new()) == NULL) 245 goto out; 246 247 fido_dev_get_cbor_info(dev, ci); 248 249 for (size_t i = 0; i < fido_cbor_info_versions_len(ci); i++) { 250 char * const *sa = fido_cbor_info_versions_ptr(ci); 251 consume(sa[i], strlen(sa[i])); 252 } 253 254 for (size_t i = 0; i < fido_cbor_info_extensions_len(ci); i++) { 255 char * const *sa = fido_cbor_info_extensions_ptr(ci); 256 consume(sa[i], strlen(sa[i])); 257 } 258 259 for (size_t i = 0; i < fido_cbor_info_transports_len(ci); i++) { 260 char * const *sa = fido_cbor_info_transports_ptr(ci); 261 consume(sa[i], strlen(sa[i])); 262 } 263 264 for (size_t i = 0; i < fido_cbor_info_options_len(ci); i++) { 265 char * const *sa = fido_cbor_info_options_name_ptr(ci); 266 const bool *va = fido_cbor_info_options_value_ptr(ci); 267 consume(sa[i], strlen(sa[i])); 268 consume(&va[i], sizeof(va[i])); 269 } 270 271 /* +1 on purpose */ 272 for (size_t i = 0; i <= fido_cbor_info_algorithm_count(ci); i++) { 273 const char *type = fido_cbor_info_algorithm_type(ci, i); 274 int cose = fido_cbor_info_algorithm_cose(ci, i); 275 consume_str(type); 276 consume(&cose, sizeof(cose)); 277 } 278 279 n = fido_cbor_info_maxmsgsiz(ci); 280 consume(&n, sizeof(n)); 281 282 n = fido_cbor_info_maxcredbloblen(ci); 283 consume(&n, sizeof(n)); 284 285 n = fido_cbor_info_maxcredcntlst(ci); 286 consume(&n, sizeof(n)); 287 288 n = fido_cbor_info_maxcredidlen(ci); 289 consume(&n, sizeof(n)); 290 291 n = fido_cbor_info_fwversion(ci); 292 consume(&n, sizeof(n)); 293 294 consume(fido_cbor_info_aaguid_ptr(ci), fido_cbor_info_aaguid_len(ci)); 295 consume(fido_cbor_info_protocols_ptr(ci), 296 fido_cbor_info_protocols_len(ci)); 297 298 out: 299 fido_dev_close(dev); 300 fido_dev_free(&dev); 301 302 fido_cbor_info_free(&ci); 303 } 304 305 static void 306 dev_set_pin(const struct param *p) 307 { 308 fido_dev_t *dev; 309 310 set_wire_data(p->set_pin_wire_data.body, p->set_pin_wire_data.len); 311 312 if ((dev = open_dev(0)) == NULL) 313 return; 314 315 fido_dev_set_pin(dev, p->pin1, NULL); 316 fido_dev_close(dev); 317 fido_dev_free(&dev); 318 } 319 320 static void 321 dev_change_pin(const struct param *p) 322 { 323 fido_dev_t *dev; 324 325 set_wire_data(p->change_pin_wire_data.body, p->change_pin_wire_data.len); 326 327 if ((dev = open_dev(0)) == NULL) 328 return; 329 330 fido_dev_set_pin(dev, p->pin2, p->pin1); 331 fido_dev_close(dev); 332 fido_dev_free(&dev); 333 } 334 335 static void 336 dev_get_retry_count(const struct param *p) 337 { 338 fido_dev_t *dev; 339 int n = 0; 340 341 set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len); 342 343 if ((dev = open_dev(0)) == NULL) 344 return; 345 346 fido_dev_get_retry_count(dev, &n); 347 consume(&n, sizeof(n)); 348 fido_dev_close(dev); 349 fido_dev_free(&dev); 350 } 351 352 static void 353 dev_get_uv_retry_count(const struct param *p) 354 { 355 fido_dev_t *dev; 356 int n = 0; 357 358 set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len); 359 360 if ((dev = open_dev(0)) == NULL) 361 return; 362 363 fido_dev_get_uv_retry_count(dev, &n); 364 consume(&n, sizeof(n)); 365 fido_dev_close(dev); 366 fido_dev_free(&dev); 367 } 368 369 static void 370 dev_enable_entattest(const struct param *p) 371 { 372 fido_dev_t *dev; 373 const char *pin; 374 int r; 375 376 set_wire_data(p->config_wire_data.body, p->config_wire_data.len); 377 if ((dev = open_dev(0)) == NULL) 378 return; 379 pin = p->pin1; 380 if (strlen(pin) == 0) 381 pin = NULL; 382 r = fido_dev_enable_entattest(dev, pin); 383 consume_str(fido_strerr(r)); 384 fido_dev_close(dev); 385 fido_dev_free(&dev); 386 } 387 388 static void 389 dev_toggle_always_uv(const struct param *p) 390 { 391 fido_dev_t *dev; 392 const char *pin; 393 int r; 394 395 set_wire_data(p->config_wire_data.body, p->config_wire_data.len); 396 if ((dev = open_dev(0)) == NULL) 397 return; 398 pin = p->pin1; 399 if (strlen(pin) == 0) 400 pin = NULL; 401 r = fido_dev_toggle_always_uv(dev, pin); 402 consume_str(fido_strerr(r)); 403 fido_dev_close(dev); 404 fido_dev_free(&dev); 405 } 406 407 static void 408 dev_force_pin_change(const struct param *p) 409 { 410 fido_dev_t *dev; 411 const char *pin; 412 int r; 413 414 set_wire_data(p->config_wire_data.body, p->config_wire_data.len); 415 if ((dev = open_dev(0)) == NULL) 416 return; 417 pin = p->pin1; 418 if (strlen(pin) == 0) 419 pin = NULL; 420 r = fido_dev_force_pin_change(dev, pin); 421 consume_str(fido_strerr(r)); 422 fido_dev_close(dev); 423 fido_dev_free(&dev); 424 } 425 426 static void 427 dev_set_pin_minlen(const struct param *p) 428 { 429 fido_dev_t *dev; 430 const char *pin; 431 int r; 432 433 set_wire_data(p->config_wire_data.body, p->config_wire_data.len); 434 if ((dev = open_dev(0)) == NULL) 435 return; 436 pin = p->pin1; 437 if (strlen(pin) == 0) 438 pin = NULL; 439 r = fido_dev_set_pin_minlen(dev, strlen(p->pin2), pin); 440 consume_str(fido_strerr(r)); 441 fido_dev_close(dev); 442 fido_dev_free(&dev); 443 } 444 445 static void 446 dev_set_pin_minlen_rpid(const struct param *p) 447 { 448 fido_dev_t *dev; 449 const char *rpid[MAXRPID]; 450 const char *pin; 451 size_t n; 452 int r; 453 454 set_wire_data(p->config_wire_data.body, p->config_wire_data.len); 455 if ((dev = open_dev(0)) == NULL) 456 return; 457 n = uniform_random(MAXRPID); 458 for (size_t i = 0; i < n; i++) 459 rpid[i] = dummy_rp_id; 460 pin = p->pin1; 461 if (strlen(pin) == 0) 462 pin = NULL; 463 r = fido_dev_set_pin_minlen_rpid(dev, rpid, n, pin); 464 consume_str(fido_strerr(r)); 465 fido_dev_close(dev); 466 fido_dev_free(&dev); 467 } 468 469 void 470 test(const struct param *p) 471 { 472 prng_init((unsigned int)p->seed); 473 fuzz_clock_reset(); 474 fido_init(FIDO_DEBUG); 475 fido_set_log_handler(consume_str); 476 477 dev_reset(p); 478 dev_get_cbor_info(p); 479 dev_set_pin(p); 480 dev_change_pin(p); 481 dev_get_retry_count(p); 482 dev_get_uv_retry_count(p); 483 dev_enable_entattest(p); 484 dev_toggle_always_uv(p); 485 dev_force_pin_change(p); 486 dev_set_pin_minlen(p); 487 dev_set_pin_minlen_rpid(p); 488 } 489 490 void 491 mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN 492 { 493 if (flags & MUTATE_SEED) 494 p->seed = (int)seed; 495 496 if (flags & MUTATE_PARAM) { 497 mutate_string(p->pin1); 498 mutate_string(p->pin2); 499 } 500 501 if (flags & MUTATE_WIREDATA) { 502 mutate_blob(&p->reset_wire_data); 503 mutate_blob(&p->info_wire_data); 504 mutate_blob(&p->set_pin_wire_data); 505 mutate_blob(&p->change_pin_wire_data); 506 mutate_blob(&p->retry_wire_data); 507 } 508 } 509