1 /* 2 * Copyright (c) 2018-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 "fido.h" 9 10 #ifndef TLS 11 #define TLS 12 #endif 13 14 static TLS bool disable_u2f_fallback; 15 16 #ifdef FIDO_FUZZ 17 static void 18 set_random_report_len(fido_dev_t *dev) 19 { 20 dev->rx_len = CTAP_MIN_REPORT_LEN + 21 uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1); 22 dev->tx_len = CTAP_MIN_REPORT_LEN + 23 uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1); 24 } 25 #endif 26 27 static void 28 fido_dev_set_extension_flags(fido_dev_t *dev, const fido_cbor_info_t *info) 29 { 30 char * const *ptr = fido_cbor_info_extensions_ptr(info); 31 size_t len = fido_cbor_info_extensions_len(info); 32 33 for (size_t i = 0; i < len; i++) 34 if (strcmp(ptr[i], "credProtect") == 0) 35 dev->flags |= FIDO_DEV_CRED_PROT; 36 } 37 38 static void 39 fido_dev_set_option_flags(fido_dev_t *dev, const fido_cbor_info_t *info) 40 { 41 char * const *ptr = fido_cbor_info_options_name_ptr(info); 42 const bool *val = fido_cbor_info_options_value_ptr(info); 43 size_t len = fido_cbor_info_options_len(info); 44 45 for (size_t i = 0; i < len; i++) 46 if (strcmp(ptr[i], "clientPin") == 0) { 47 dev->flags |= val[i] ? 48 FIDO_DEV_PIN_SET : FIDO_DEV_PIN_UNSET; 49 } else if (strcmp(ptr[i], "credMgmt") == 0) { 50 if (val[i]) 51 dev->flags |= FIDO_DEV_CREDMAN; 52 } else if (strcmp(ptr[i], "credentialMgmtPreview") == 0) { 53 if (val[i]) 54 dev->flags |= FIDO_DEV_CREDMAN_PRE; 55 } else if (strcmp(ptr[i], "uv") == 0) { 56 dev->flags |= val[i] ? 57 FIDO_DEV_UV_SET : FIDO_DEV_UV_UNSET; 58 } else if (strcmp(ptr[i], "pinUvAuthToken") == 0) { 59 if (val[i]) 60 dev->flags |= FIDO_DEV_TOKEN_PERMS; 61 } else if (strcmp(ptr[i], "bioEnroll") == 0) { 62 dev->flags |= val[i] ? 63 FIDO_DEV_BIO_SET : FIDO_DEV_BIO_UNSET; 64 } 65 } 66 67 static void 68 fido_dev_set_protocol_flags(fido_dev_t *dev, const fido_cbor_info_t *info) 69 { 70 const uint8_t *ptr = fido_cbor_info_protocols_ptr(info); 71 size_t len = fido_cbor_info_protocols_len(info); 72 73 for (size_t i = 0; i < len; i++) 74 switch (ptr[i]) { 75 case CTAP_PIN_PROTOCOL1: 76 dev->flags |= FIDO_DEV_PIN_PROTOCOL1; 77 break; 78 case CTAP_PIN_PROTOCOL2: 79 dev->flags |= FIDO_DEV_PIN_PROTOCOL2; 80 break; 81 default: 82 fido_log_debug("%s: unknown protocol %u", __func__, 83 ptr[i]); 84 break; 85 } 86 } 87 88 static void 89 fido_dev_set_flags(fido_dev_t *dev, const fido_cbor_info_t *info) 90 { 91 fido_dev_set_extension_flags(dev, info); 92 fido_dev_set_option_flags(dev, info); 93 fido_dev_set_protocol_flags(dev, info); 94 } 95 96 static int 97 fido_dev_open_tx(fido_dev_t *dev, const char *path, int *ms) 98 { 99 int r; 100 101 if (dev->io_handle != NULL) { 102 fido_log_debug("%s: handle=%p", __func__, dev->io_handle); 103 return (FIDO_ERR_INVALID_ARGUMENT); 104 } 105 106 if (dev->io.open == NULL || dev->io.close == NULL) { 107 fido_log_debug("%s: NULL open/close", __func__); 108 return (FIDO_ERR_INVALID_ARGUMENT); 109 } 110 111 if (dev->cid != CTAP_CID_BROADCAST) { 112 fido_log_debug("%s: cid=0x%x", __func__, dev->cid); 113 return (FIDO_ERR_INVALID_ARGUMENT); 114 } 115 116 if (fido_get_random(&dev->nonce, sizeof(dev->nonce)) < 0) { 117 fido_log_debug("%s: fido_get_random", __func__); 118 return (FIDO_ERR_INTERNAL); 119 } 120 121 if ((dev->io_handle = dev->io.open(path)) == NULL) { 122 fido_log_debug("%s: dev->io.open", __func__); 123 return (FIDO_ERR_INTERNAL); 124 } 125 126 if (dev->io_own) { 127 dev->rx_len = CTAP_MAX_REPORT_LEN; 128 dev->tx_len = CTAP_MAX_REPORT_LEN; 129 } else { 130 dev->rx_len = fido_hid_report_in_len(dev->io_handle); 131 dev->tx_len = fido_hid_report_out_len(dev->io_handle); 132 } 133 134 #ifdef FIDO_FUZZ 135 set_random_report_len(dev); 136 #endif 137 138 if (dev->rx_len < CTAP_MIN_REPORT_LEN || 139 dev->rx_len > CTAP_MAX_REPORT_LEN) { 140 fido_log_debug("%s: invalid rx_len %zu", __func__, dev->rx_len); 141 r = FIDO_ERR_RX; 142 goto fail; 143 } 144 145 if (dev->tx_len < CTAP_MIN_REPORT_LEN || 146 dev->tx_len > CTAP_MAX_REPORT_LEN) { 147 fido_log_debug("%s: invalid tx_len %zu", __func__, dev->tx_len); 148 r = FIDO_ERR_TX; 149 goto fail; 150 } 151 152 if (fido_tx(dev, CTAP_CMD_INIT, &dev->nonce, sizeof(dev->nonce), 153 ms) < 0) { 154 fido_log_debug("%s: fido_tx", __func__); 155 r = FIDO_ERR_TX; 156 goto fail; 157 } 158 159 return (FIDO_OK); 160 fail: 161 dev->io.close(dev->io_handle); 162 dev->io_handle = NULL; 163 164 return (r); 165 } 166 167 static int 168 fido_dev_open_rx(fido_dev_t *dev, int *ms) 169 { 170 fido_cbor_info_t *info = NULL; 171 int reply_len; 172 int r; 173 174 if ((reply_len = fido_rx(dev, CTAP_CMD_INIT, &dev->attr, 175 sizeof(dev->attr), ms)) < 0) { 176 fido_log_debug("%s: fido_rx", __func__); 177 r = FIDO_ERR_RX; 178 goto fail; 179 } 180 181 #ifdef FIDO_FUZZ 182 dev->attr.nonce = dev->nonce; 183 #endif 184 185 if ((size_t)reply_len != sizeof(dev->attr) || 186 dev->attr.nonce != dev->nonce) { 187 fido_log_debug("%s: invalid nonce", __func__); 188 r = FIDO_ERR_RX; 189 goto fail; 190 } 191 192 dev->flags = 0; 193 dev->cid = dev->attr.cid; 194 195 if (fido_dev_is_fido2(dev)) { 196 if ((info = fido_cbor_info_new()) == NULL) { 197 fido_log_debug("%s: fido_cbor_info_new", __func__); 198 r = FIDO_ERR_INTERNAL; 199 goto fail; 200 } 201 if ((r = fido_dev_get_cbor_info_wait(dev, info, 202 ms)) != FIDO_OK) { 203 fido_log_debug("%s: fido_dev_cbor_info_wait: %d", 204 __func__, r); 205 if (disable_u2f_fallback) 206 goto fail; 207 fido_log_debug("%s: falling back to u2f", __func__); 208 fido_dev_force_u2f(dev); 209 } else { 210 fido_dev_set_flags(dev, info); 211 } 212 } 213 214 if (fido_dev_is_fido2(dev) && info != NULL) { 215 dev->maxmsgsize = fido_cbor_info_maxmsgsiz(info); 216 fido_log_debug("%s: FIDO_MAXMSG=%d, maxmsgsiz=%lu", __func__, 217 FIDO_MAXMSG, (unsigned long)dev->maxmsgsize); 218 } 219 220 r = FIDO_OK; 221 fail: 222 fido_cbor_info_free(&info); 223 224 if (r != FIDO_OK) { 225 dev->io.close(dev->io_handle); 226 dev->io_handle = NULL; 227 } 228 229 return (r); 230 } 231 232 static int 233 fido_dev_open_wait(fido_dev_t *dev, const char *path, int *ms) 234 { 235 int r; 236 237 #ifdef USE_WINHELLO 238 if (strcmp(path, FIDO_WINHELLO_PATH) == 0) 239 return (fido_winhello_open(dev)); 240 #endif 241 if ((r = fido_dev_open_tx(dev, path, ms)) != FIDO_OK || 242 (r = fido_dev_open_rx(dev, ms)) != FIDO_OK) 243 return (r); 244 245 return (FIDO_OK); 246 } 247 248 static void 249 run_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen, 250 const char *type, int (*manifest)(fido_dev_info_t *, size_t, size_t *)) 251 { 252 size_t ndevs = 0; 253 int r; 254 255 if (*olen >= ilen) { 256 fido_log_debug("%s: skipping %s", __func__, type); 257 return; 258 } 259 if ((r = manifest(devlist + *olen, ilen - *olen, &ndevs)) != FIDO_OK) 260 fido_log_debug("%s: %s: 0x%x", __func__, type, r); 261 fido_log_debug("%s: found %zu %s device%s", __func__, ndevs, type, 262 ndevs == 1 ? "" : "s"); 263 *olen += ndevs; 264 } 265 266 int 267 fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) 268 { 269 *olen = 0; 270 271 run_manifest(devlist, ilen, olen, "hid", fido_hid_manifest); 272 #ifdef USE_NFC 273 run_manifest(devlist, ilen, olen, "nfc", fido_nfc_manifest); 274 #endif 275 #ifdef USE_PCSC 276 run_manifest(devlist, ilen, olen, "pcsc", fido_pcsc_manifest); 277 #endif 278 #ifdef USE_WINHELLO 279 run_manifest(devlist, ilen, olen, "winhello", fido_winhello_manifest); 280 #endif 281 282 return (FIDO_OK); 283 } 284 285 int 286 fido_dev_open_with_info(fido_dev_t *dev) 287 { 288 int ms = dev->timeout_ms; 289 290 if (dev->path == NULL) 291 return (FIDO_ERR_INVALID_ARGUMENT); 292 293 return (fido_dev_open_wait(dev, dev->path, &ms)); 294 } 295 296 int 297 fido_dev_open(fido_dev_t *dev, const char *path) 298 { 299 int ms = dev->timeout_ms; 300 301 #ifdef USE_NFC 302 if (fido_is_nfc(path) && fido_dev_set_nfc(dev) < 0) { 303 fido_log_debug("%s: fido_dev_set_nfc", __func__); 304 return FIDO_ERR_INTERNAL; 305 } 306 #endif 307 #ifdef USE_PCSC 308 if (fido_is_pcsc(path) && fido_dev_set_pcsc(dev) < 0) { 309 fido_log_debug("%s: fido_dev_set_pcsc", __func__); 310 return FIDO_ERR_INTERNAL; 311 } 312 #endif 313 314 return (fido_dev_open_wait(dev, path, &ms)); 315 } 316 317 int 318 fido_dev_close(fido_dev_t *dev) 319 { 320 #ifdef USE_WINHELLO 321 if (dev->flags & FIDO_DEV_WINHELLO) 322 return (fido_winhello_close(dev)); 323 #endif 324 if (dev->io_handle == NULL || dev->io.close == NULL) 325 return (FIDO_ERR_INVALID_ARGUMENT); 326 327 dev->io.close(dev->io_handle); 328 dev->io_handle = NULL; 329 dev->cid = CTAP_CID_BROADCAST; 330 331 return (FIDO_OK); 332 } 333 334 int 335 fido_dev_set_sigmask(fido_dev_t *dev, const fido_sigset_t *sigmask) 336 { 337 if (dev->io_handle == NULL || sigmask == NULL) 338 return (FIDO_ERR_INVALID_ARGUMENT); 339 340 #ifdef USE_NFC 341 if (dev->transport.rx == fido_nfc_rx && dev->io.read == fido_nfc_read) 342 return (fido_nfc_set_sigmask(dev->io_handle, sigmask)); 343 #endif 344 if (dev->transport.rx == NULL && dev->io.read == fido_hid_read) 345 return (fido_hid_set_sigmask(dev->io_handle, sigmask)); 346 347 return (FIDO_ERR_INVALID_ARGUMENT); 348 } 349 350 int 351 fido_dev_cancel(fido_dev_t *dev) 352 { 353 int ms = dev->timeout_ms; 354 355 #ifdef USE_WINHELLO 356 if (dev->flags & FIDO_DEV_WINHELLO) 357 return (fido_winhello_cancel(dev)); 358 #endif 359 if (fido_dev_is_fido2(dev) == false) 360 return (FIDO_ERR_INVALID_ARGUMENT); 361 if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0, &ms) < 0) 362 return (FIDO_ERR_TX); 363 364 return (FIDO_OK); 365 } 366 367 int 368 fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) 369 { 370 if (dev->io_handle != NULL) { 371 fido_log_debug("%s: non-NULL handle", __func__); 372 return (FIDO_ERR_INVALID_ARGUMENT); 373 } 374 375 if (io == NULL || io->open == NULL || io->close == NULL || 376 io->read == NULL || io->write == NULL) { 377 fido_log_debug("%s: NULL function", __func__); 378 return (FIDO_ERR_INVALID_ARGUMENT); 379 } 380 381 dev->io = *io; 382 dev->io_own = true; 383 384 return (FIDO_OK); 385 } 386 387 int 388 fido_dev_set_transport_functions(fido_dev_t *dev, const fido_dev_transport_t *t) 389 { 390 if (dev->io_handle != NULL) { 391 fido_log_debug("%s: non-NULL handle", __func__); 392 return (FIDO_ERR_INVALID_ARGUMENT); 393 } 394 395 dev->transport = *t; 396 dev->io_own = true; 397 398 return (FIDO_OK); 399 } 400 401 void * 402 fido_dev_io_handle(const fido_dev_t *dev) 403 { 404 405 return (dev->io_handle); 406 } 407 408 void 409 fido_init(int flags) 410 { 411 if (flags & FIDO_DEBUG || getenv("FIDO_DEBUG") != NULL) 412 fido_log_init(); 413 414 disable_u2f_fallback = (flags & FIDO_DISABLE_U2F_FALLBACK); 415 } 416 417 fido_dev_t * 418 fido_dev_new(void) 419 { 420 fido_dev_t *dev; 421 422 if ((dev = calloc(1, sizeof(*dev))) == NULL) 423 return (NULL); 424 425 dev->cid = CTAP_CID_BROADCAST; 426 dev->timeout_ms = -1; 427 dev->io = (fido_dev_io_t) { 428 &fido_hid_open, 429 &fido_hid_close, 430 &fido_hid_read, 431 &fido_hid_write, 432 }; 433 434 return (dev); 435 } 436 437 fido_dev_t * 438 fido_dev_new_with_info(const fido_dev_info_t *di) 439 { 440 fido_dev_t *dev; 441 442 if ((dev = calloc(1, sizeof(*dev))) == NULL) 443 return (NULL); 444 445 #if 0 446 if (di->io.open == NULL || di->io.close == NULL || 447 di->io.read == NULL || di->io.write == NULL) { 448 fido_log_debug("%s: NULL function", __func__); 449 fido_dev_free(&dev); 450 return (NULL); 451 } 452 #endif 453 454 dev->io = di->io; 455 dev->io_own = di->transport.tx != NULL || di->transport.rx != NULL; 456 dev->transport = di->transport; 457 dev->cid = CTAP_CID_BROADCAST; 458 dev->timeout_ms = -1; 459 460 if ((dev->path = strdup(di->path)) == NULL) { 461 fido_log_debug("%s: strdup", __func__); 462 fido_dev_free(&dev); 463 return (NULL); 464 } 465 466 return (dev); 467 } 468 469 void 470 fido_dev_free(fido_dev_t **dev_p) 471 { 472 fido_dev_t *dev; 473 474 if (dev_p == NULL || (dev = *dev_p) == NULL) 475 return; 476 477 free(dev->path); 478 free(dev); 479 480 *dev_p = NULL; 481 } 482 483 uint8_t 484 fido_dev_protocol(const fido_dev_t *dev) 485 { 486 return (dev->attr.protocol); 487 } 488 489 uint8_t 490 fido_dev_major(const fido_dev_t *dev) 491 { 492 return (dev->attr.major); 493 } 494 495 uint8_t 496 fido_dev_minor(const fido_dev_t *dev) 497 { 498 return (dev->attr.minor); 499 } 500 501 uint8_t 502 fido_dev_build(const fido_dev_t *dev) 503 { 504 return (dev->attr.build); 505 } 506 507 uint8_t 508 fido_dev_flags(const fido_dev_t *dev) 509 { 510 return (dev->attr.flags); 511 } 512 513 bool 514 fido_dev_is_fido2(const fido_dev_t *dev) 515 { 516 return (dev->attr.flags & FIDO_CAP_CBOR); 517 } 518 519 bool 520 fido_dev_is_winhello(const fido_dev_t *dev) 521 { 522 return (dev->flags & FIDO_DEV_WINHELLO); 523 } 524 525 bool 526 fido_dev_supports_pin(const fido_dev_t *dev) 527 { 528 return (dev->flags & (FIDO_DEV_PIN_SET|FIDO_DEV_PIN_UNSET)); 529 } 530 531 bool 532 fido_dev_has_pin(const fido_dev_t *dev) 533 { 534 return (dev->flags & FIDO_DEV_PIN_SET); 535 } 536 537 bool 538 fido_dev_supports_cred_prot(const fido_dev_t *dev) 539 { 540 return (dev->flags & FIDO_DEV_CRED_PROT); 541 } 542 543 bool 544 fido_dev_supports_credman(const fido_dev_t *dev) 545 { 546 return (dev->flags & (FIDO_DEV_CREDMAN|FIDO_DEV_CREDMAN_PRE)); 547 } 548 549 bool 550 fido_dev_supports_uv(const fido_dev_t *dev) 551 { 552 return (dev->flags & (FIDO_DEV_UV_SET|FIDO_DEV_UV_UNSET)); 553 } 554 555 bool 556 fido_dev_has_uv(const fido_dev_t *dev) 557 { 558 return (dev->flags & FIDO_DEV_UV_SET); 559 } 560 561 bool 562 fido_dev_supports_permissions(const fido_dev_t *dev) 563 { 564 return (dev->flags & FIDO_DEV_TOKEN_PERMS); 565 } 566 567 void 568 fido_dev_force_u2f(fido_dev_t *dev) 569 { 570 dev->attr.flags &= (uint8_t)~FIDO_CAP_CBOR; 571 dev->flags = 0; 572 } 573 574 void 575 fido_dev_force_fido2(fido_dev_t *dev) 576 { 577 dev->attr.flags |= FIDO_CAP_CBOR; 578 } 579 580 uint8_t 581 fido_dev_get_pin_protocol(const fido_dev_t *dev) 582 { 583 if (dev->flags & FIDO_DEV_PIN_PROTOCOL2) 584 return (CTAP_PIN_PROTOCOL2); 585 else if (dev->flags & FIDO_DEV_PIN_PROTOCOL1) 586 return (CTAP_PIN_PROTOCOL1); 587 588 return (0); 589 } 590 591 uint64_t 592 fido_dev_maxmsgsize(const fido_dev_t *dev) 593 { 594 return (dev->maxmsgsize); 595 } 596 597 int 598 fido_dev_set_timeout(fido_dev_t *dev, int ms) 599 { 600 if (ms < -1) 601 return (FIDO_ERR_INVALID_ARGUMENT); 602 603 dev->timeout_ms = ms; 604 605 return (FIDO_OK); 606 } 607