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