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