1 /* 2 * Copyright (C) 2014-2019 Yubico AB - See COPYING 3 */ 4 5 #include <fido.h> 6 #include <fido/es256.h> 7 #include <fido/rs256.h> 8 9 #include <openssl/ec.h> 10 #include <openssl/obj_mac.h> 11 12 #include <stdbool.h> 13 #include <stdlib.h> 14 #include <fcntl.h> 15 #include <sys/stat.h> 16 #include <stdarg.h> 17 #include <syslog.h> 18 #include <pwd.h> 19 #include <errno.h> 20 #include <unistd.h> 21 #include <string.h> 22 23 #include "b64.h" 24 #include "util.h" 25 26 static int hex_decode(const char *ascii_hex, unsigned char **blob, 27 size_t *blob_len) { 28 *blob = NULL; 29 *blob_len = 0; 30 31 if (ascii_hex == NULL || (strlen(ascii_hex) % 2) != 0) 32 return (0); 33 34 *blob_len = strlen(ascii_hex) / 2; 35 *blob = calloc(1, *blob_len); 36 if (*blob == NULL) 37 return (0); 38 39 for (size_t i = 0; i < *blob_len; i++) { 40 unsigned int c; 41 int n = -1; 42 int r = sscanf(ascii_hex, "%02x%n", &c, &n); 43 if (r != 1 || n != 2 || c > UCHAR_MAX) { 44 free(*blob); 45 *blob = NULL; 46 *blob_len = 0; 47 return (0); 48 } 49 (*blob)[i] = (unsigned char) c; 50 ascii_hex += n; 51 } 52 53 return (1); 54 } 55 56 static char *normal_b64(const char *websafe_b64) { 57 char *b64; 58 char *p; 59 size_t n; 60 61 n = strlen(websafe_b64); 62 if (n > SIZE_MAX - 3) 63 return (NULL); 64 65 b64 = calloc(1, n + 3); 66 if (b64 == NULL) 67 return (NULL); 68 69 memcpy(b64, websafe_b64, n); 70 p = b64; 71 72 while ((p = strpbrk(p, "-_")) != NULL) { 73 switch (*p) { 74 case '-': 75 *p++ = '+'; 76 break; 77 case '_': 78 *p++ = '/'; 79 break; 80 } 81 } 82 83 switch (n % 4) { 84 case 1: 85 b64[n] = '='; 86 break; 87 case 2: 88 case 3: 89 b64[n] = '='; 90 b64[n + 1] = '='; 91 break; 92 } 93 94 return (b64); 95 } 96 97 static es256_pk_t *translate_old_format_pubkey(const unsigned char *pk, 98 size_t pk_len) { 99 es256_pk_t *es256_pk = NULL; 100 EC_KEY *ec = NULL; 101 EC_POINT *q = NULL; 102 const EC_GROUP *g = NULL; 103 int ok = 0; 104 105 if ((ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)) == NULL || 106 (g = EC_KEY_get0_group(ec)) == NULL) 107 goto fail; 108 109 if ((q = EC_POINT_new(g)) == NULL || 110 !EC_POINT_oct2point(g, q, pk, pk_len, NULL) || 111 !EC_KEY_set_public_key(ec, q)) 112 goto fail; 113 114 es256_pk = es256_pk_new(); 115 if (es256_pk == NULL || es256_pk_from_EC_KEY(es256_pk, ec) < 0) 116 goto fail; 117 118 ok = 1; 119 fail: 120 if (ec != NULL) 121 EC_KEY_free(ec); 122 if (q != NULL) 123 EC_POINT_free(q); 124 if (!ok) 125 es256_pk_free(&es256_pk); 126 127 return (es256_pk); 128 } 129 130 int get_devices_from_authfile(const char *authfile, const char *username, 131 unsigned max_devs, int verbose, FILE *debug_file, 132 device_t *devices, unsigned *n_devs) { 133 134 char *buf = NULL; 135 char *s_user, *s_token; 136 int retval = 0; 137 int fd = -1; 138 struct stat st; 139 struct passwd *pw = NULL, pw_s; 140 char buffer[BUFSIZE]; 141 int gpu_ret; 142 FILE *opwfile = NULL; 143 unsigned i; 144 145 /* Ensure we never return uninitialized count. */ 146 *n_devs = 0; 147 148 fd = open(authfile, O_RDONLY | O_CLOEXEC | O_NOCTTY); 149 if (fd < 0) { 150 if (verbose) 151 D(debug_file, "Cannot open file: %s (%s)", authfile, strerror(errno)); 152 goto err; 153 } 154 155 if (fstat(fd, &st) < 0) { 156 if (verbose) 157 D(debug_file, "Cannot stat file: %s (%s)", authfile, strerror(errno)); 158 goto err; 159 } 160 161 if (!S_ISREG(st.st_mode)) { 162 if (verbose) 163 D(debug_file, "%s is not a regular file", authfile); 164 goto err; 165 } 166 167 if (st.st_size == 0) { 168 if (verbose) 169 D(debug_file, "File %s is empty", authfile); 170 goto err; 171 } 172 173 gpu_ret = getpwuid_r(st.st_uid, &pw_s, buffer, sizeof(buffer), &pw); 174 if (gpu_ret != 0 || pw == NULL) { 175 D(debug_file, "Unable to retrieve credentials for uid %u, (%s)", st.st_uid, 176 strerror(errno)); 177 goto err; 178 } 179 180 if (strcmp(pw->pw_name, username) != 0 && strcmp(pw->pw_name, "root") != 0) { 181 if (strcmp(username, "root") != 0) { 182 D(debug_file, 183 "The owner of the authentication file is neither %s nor root", 184 username); 185 } else { 186 D(debug_file, "The owner of the authentication file is not root"); 187 } 188 goto err; 189 } 190 191 opwfile = fdopen(fd, "r"); 192 if (opwfile == NULL) { 193 if (verbose) 194 D(debug_file, "fdopen: %s", strerror(errno)); 195 goto err; 196 } else { 197 fd = -1; /* fd belongs to opwfile */ 198 } 199 200 buf = malloc(sizeof(char) * (DEVSIZE * max_devs)); 201 if (!buf) { 202 if (verbose) 203 D(debug_file, "Unable to allocate memory"); 204 goto err; 205 } 206 207 retval = -2; 208 while (fgets(buf, (int) (DEVSIZE * (max_devs - 1)), opwfile)) { 209 char *saveptr = NULL; 210 size_t len = strlen(buf); 211 if (len > 0 && buf[len - 1] == '\n') 212 buf[len - 1] = '\0'; 213 214 if (verbose) 215 D(debug_file, "Authorization line: %s", buf); 216 217 s_user = strtok_r(buf, ":", &saveptr); 218 if (s_user && strcmp(username, s_user) == 0) { 219 if (verbose) 220 D(debug_file, "Matched user: %s", s_user); 221 222 retval = -1; // We found at least one line for the user 223 224 // only keep last line for this user 225 for (i = 0; i < *n_devs; i++) { 226 free(devices[i].keyHandle); 227 free(devices[i].publicKey); 228 free(devices[i].coseType); 229 free(devices[i].attributes); 230 devices[i].keyHandle = NULL; 231 devices[i].publicKey = NULL; 232 devices[i].coseType = NULL; 233 devices[i].attributes = NULL; 234 devices[i].old_format = 0; 235 } 236 *n_devs = 0; 237 238 i = 0; 239 while ((s_token = strtok_r(NULL, ",", &saveptr)) != NULL) { 240 if ((*n_devs)++ > max_devs - 1) { 241 *n_devs = max_devs; 242 if (verbose) 243 D(debug_file, 244 "Found more than %d devices, ignoring the remaining ones", 245 max_devs); 246 break; 247 } 248 249 devices[i].keyHandle = NULL; 250 devices[i].publicKey = NULL; 251 devices[i].coseType = NULL; 252 devices[i].attributes = NULL; 253 devices[i].old_format = 0; 254 255 if (verbose) 256 D(debug_file, "KeyHandle for device number %d: %s", i + 1, s_token); 257 258 devices[i].keyHandle = strdup(s_token); 259 260 if (!devices[i].keyHandle) { 261 if (verbose) 262 D(debug_file, "Unable to allocate memory for keyHandle number %d", 263 i); 264 goto err; 265 } 266 267 if (!strcmp(devices[i].keyHandle, "*") && verbose) 268 D(debug_file, "Credential is resident"); 269 270 s_token = strtok_r(NULL, ",", &saveptr); 271 272 if (!s_token) { 273 if (verbose) 274 D(debug_file, "Unable to retrieve publicKey number %d", i + 1); 275 goto err; 276 } 277 278 if (verbose) 279 D(debug_file, "publicKey for device number %d: %s", i + 1, s_token); 280 281 devices[i].publicKey = strdup(s_token); 282 283 if (!devices[i].publicKey) { 284 if (verbose) 285 D(debug_file, "Unable to allocate memory for publicKey number %d", 286 i); 287 goto err; 288 } 289 290 s_token = strtok_r(NULL, ",", &saveptr); 291 292 devices[i].old_format = 0; 293 294 if (!s_token) { 295 if (verbose) { 296 D(debug_file, "Unable to retrieve COSE type %d", i + 1); 297 D(debug_file, "Assuming ES256 (backwards compatibility)"); 298 } 299 devices[i].old_format = 1; 300 devices[i].coseType = strdup("es256"); 301 } else { 302 if (verbose) 303 D(debug_file, "COSE type for device number %d: %s", i + 1, s_token); 304 devices[i].coseType = strdup(s_token); 305 } 306 307 if (!devices[i].coseType) { 308 if (verbose) 309 D(debug_file, "Unable to allocate memory for COSE type number %d", 310 i); 311 goto err; 312 } 313 314 s_token = strtok_r(NULL, ":", &saveptr); 315 316 if (!s_token) { 317 if (verbose) { 318 D(debug_file, "Unable to retrieve attributes %d", i + 1); 319 D(debug_file, "Assuming 'p' (backwards compatibility)"); 320 } 321 devices[i].attributes = strdup("p"); 322 } else { 323 if (verbose) 324 D(debug_file, "Attributes for device number %d: %s", i + 1, 325 s_token); 326 devices[i].attributes = strdup(s_token); 327 } 328 329 if (!devices[i].attributes) { 330 if (verbose) 331 D(debug_file, "Unable to allocate memory for attributes number %d", 332 i); 333 goto err; 334 } 335 336 if (devices[i].old_format) { 337 char *websafe_b64 = devices[i].keyHandle; 338 devices[i].keyHandle = normal_b64(websafe_b64); 339 free(websafe_b64); 340 if (!devices[i].keyHandle) { 341 if (verbose) 342 D(debug_file, "Unable to allocate memory for keyHandle number %d", 343 i); 344 goto err; 345 } 346 } 347 348 i++; 349 } 350 } 351 } 352 353 if (verbose) 354 D(debug_file, "Found %d device(s) for user %s", *n_devs, username); 355 356 retval = 1; 357 goto out; 358 359 err: 360 for (i = 0; i < *n_devs; i++) { 361 free(devices[i].keyHandle); 362 free(devices[i].publicKey); 363 free(devices[i].coseType); 364 free(devices[i].attributes); 365 devices[i].keyHandle = NULL; 366 devices[i].publicKey = NULL; 367 devices[i].coseType = NULL; 368 devices[i].attributes = NULL; 369 } 370 371 *n_devs = 0; 372 373 out: 374 if (buf) { 375 free(buf); 376 buf = NULL; 377 } 378 379 if (opwfile) 380 fclose(opwfile); 381 382 if (fd != -1) 383 close(fd); 384 385 return retval; 386 } 387 388 void free_devices(device_t *devices, const unsigned n_devs) { 389 unsigned i; 390 391 if (!devices) 392 return; 393 394 for (i = 0; i < n_devs; i++) { 395 free(devices[i].keyHandle); 396 devices[i].keyHandle = NULL; 397 398 free(devices[i].publicKey); 399 devices[i].publicKey = NULL; 400 401 free(devices[i].coseType); 402 devices[i].coseType = NULL; 403 404 free(devices[i].attributes); 405 devices[i].attributes = NULL; 406 } 407 408 free(devices); 409 devices = NULL; 410 } 411 412 static int get_authenticators(const cfg_t *cfg, const fido_dev_info_t *devlist, 413 size_t devlist_len, fido_assert_t *assert, 414 const void *kh, fido_dev_t **authlist) { 415 const fido_dev_info_t *di = NULL; 416 fido_dev_t *dev = NULL; 417 int r; 418 size_t i; 419 size_t j; 420 421 if (cfg->debug) 422 D(cfg->debug_file, "Working with %zu authenticator(s)", devlist_len); 423 424 for (i = 0, j = 0; i < devlist_len; i++) { 425 if (cfg->debug) 426 D(cfg->debug_file, "Checking whether key exists in authenticator %zu", i); 427 428 di = fido_dev_info_ptr(devlist, i); 429 if (!di) { 430 if (cfg->debug) 431 D(cfg->debug_file, "Unable to get device pointer"); 432 continue; 433 } 434 435 if (cfg->debug) 436 D(cfg->debug_file, "Authenticator path: %s", fido_dev_info_path(di)); 437 438 dev = fido_dev_new(); 439 if (!dev) { 440 if (cfg->debug) 441 D(cfg->debug_file, "Unable to allocate device type"); 442 continue; 443 } 444 445 r = fido_dev_open(dev, fido_dev_info_path(di)); 446 if (r != FIDO_OK) { 447 if (cfg->debug) 448 D(cfg->debug_file, "Failed to open authenticator: %s (%d)", 449 fido_strerr(r), r); 450 fido_dev_free(&dev); 451 continue; 452 } 453 454 if (kh == NULL || cfg->nodetect) { 455 /* resident credential or nodetect: try all authenticators */ 456 authlist[j++] = dev; 457 } else { 458 r = fido_dev_get_assert(dev, assert, NULL); 459 if ((!fido_dev_is_fido2(dev) && r == FIDO_ERR_USER_PRESENCE_REQUIRED) || 460 (fido_dev_is_fido2(dev) && r == FIDO_OK)) { 461 authlist[j++] = dev; 462 if (cfg->debug) 463 D(cfg->debug_file, "Found key in authenticator %zu", i); 464 return (1); 465 } 466 if (cfg->debug) 467 D(cfg->debug_file, "Key not found in authenticator %zu", i); 468 469 fido_dev_close(dev); 470 fido_dev_free(&dev); 471 } 472 } 473 474 if (kh == NULL && j != 0) 475 return (1); 476 else { 477 if (cfg->debug) 478 D(cfg->debug_file, "Key not found"); 479 return (0); 480 } 481 } 482 483 int do_authentication(const cfg_t *cfg, const device_t *devices, 484 const unsigned n_devs, pam_handle_t *pamh) { 485 es256_pk_t *es256_pk = NULL; 486 rs256_pk_t *rs256_pk = NULL; 487 fido_assert_t *assert = NULL; 488 fido_dev_info_t *devlist = NULL; 489 fido_dev_t **authlist = NULL; 490 int cued = 0; 491 int r; 492 int retval = -2; 493 int cose_type; 494 size_t kh_len; 495 size_t ndevs = 0; 496 size_t ndevs_prev = 0; 497 size_t pk_len; 498 unsigned char challenge[32]; 499 unsigned char *kh = NULL; 500 unsigned char *pk = NULL; 501 unsigned i = 0; 502 fido_opt_t user_presence = FIDO_OPT_OMIT; 503 fido_opt_t user_verification = FIDO_OPT_OMIT; 504 fido_opt_t pin_verification = FIDO_OPT_OMIT; 505 char *pin = NULL; 506 507 fido_init(cfg->debug ? FIDO_DEBUG : 0); 508 509 devlist = fido_dev_info_new(64); 510 if (!devlist) { 511 if (cfg->debug) 512 D(cfg->debug_file, "Unable to allocate devlist"); 513 goto out; 514 } 515 516 r = fido_dev_info_manifest(devlist, 64, &ndevs); 517 if (r != FIDO_OK) { 518 if (cfg->debug) 519 D(cfg->debug_file, "Unable to discover device(s), %s (%d)", 520 fido_strerr(r), r); 521 goto out; 522 } 523 524 ndevs_prev = ndevs; 525 526 if (cfg->debug) 527 D(cfg->debug_file, "Device max index is %u", ndevs); 528 529 es256_pk = es256_pk_new(); 530 if (!es256_pk) { 531 if (cfg->debug) 532 D(cfg->debug_file, "Unable to allocate ES256 public key"); 533 goto out; 534 } 535 536 rs256_pk = rs256_pk_new(); 537 if (!rs256_pk) { 538 if (cfg->debug) 539 D(cfg->debug_file, "Unable to allocate RS256 public key"); 540 goto out; 541 } 542 543 authlist = calloc(64 + 1, sizeof(fido_dev_t *)); 544 if (!authlist) { 545 if (cfg->debug) 546 D(cfg->debug_file, "Unable to allocate authenticator list"); 547 goto out; 548 } 549 550 if (cfg->nodetect && cfg->debug) 551 D(cfg->debug_file, 552 "nodetect option specified, suitable key detection will be skipped"); 553 554 i = 0; 555 while (i < n_devs) { 556 retval = -2; 557 558 if (cfg->debug) 559 D(cfg->debug_file, "Attempting authentication with device number %d", 560 i + 1); 561 562 assert = fido_assert_new(); 563 if (!assert) { 564 if (cfg->debug) 565 D(cfg->debug_file, "Unable to allocate assertion"); 566 goto out; 567 } 568 569 r = fido_assert_set_rp(assert, cfg->origin); 570 if (r != FIDO_OK) { 571 if (cfg->debug) 572 D(cfg->debug_file, "Unable to set origin: %s (%d)", fido_strerr(r), r); 573 goto out; 574 } 575 576 if (!strcmp(devices[i].keyHandle, "*")) { 577 if (cfg->debug) 578 D(cfg->debug_file, "Credential is resident"); 579 } else { 580 if (cfg->debug) 581 D(cfg->debug_file, "Key handle: %s", devices[i].keyHandle); 582 if (!b64_decode(devices[i].keyHandle, (void **) &kh, &kh_len)) { 583 if (cfg->debug) 584 D(cfg->debug_file, "Failed to decode key handle"); 585 goto out; 586 } 587 588 r = fido_assert_allow_cred(assert, kh, kh_len); 589 if (r != FIDO_OK) { 590 if (cfg->debug) 591 D(cfg->debug_file, "Unable to set keyHandle: %s (%d)", fido_strerr(r), 592 r); 593 goto out; 594 } 595 } 596 597 if (devices[i].old_format) { 598 if (!hex_decode(devices[i].publicKey, &pk, &pk_len)) { 599 if (cfg->debug) 600 D(cfg->debug_file, "Failed to decode public key"); 601 goto out; 602 } 603 } else { 604 if (!b64_decode(devices[i].publicKey, (void **) &pk, &pk_len)) { 605 if (cfg->debug) 606 D(cfg->debug_file, "Failed to decode public key"); 607 goto out; 608 } 609 } 610 611 if (!strcmp(devices[i].coseType, "es256")) { 612 if (devices[i].old_format) { 613 es256_pk = translate_old_format_pubkey(pk, pk_len); 614 if (es256_pk == NULL) { 615 if (cfg->debug) 616 D(cfg->debug_file, "Failed to convert ES256 public key"); 617 } 618 } else { 619 r = es256_pk_from_ptr(es256_pk, pk, pk_len); 620 if (r != FIDO_OK) { 621 if (cfg->debug) 622 D(cfg->debug_file, "Failed to convert ES256 public key"); 623 } 624 } 625 cose_type = COSE_ES256; 626 } else if (!strcmp(devices[i].coseType, "rs256")) { 627 r = rs256_pk_from_ptr(rs256_pk, pk, pk_len); 628 if (r != FIDO_OK) { 629 if (cfg->debug) 630 D(cfg->debug_file, "Failed to convert RS256 public key"); 631 } 632 cose_type = COSE_RS256; 633 } else { 634 if (cfg->debug) 635 D(cfg->debug_file, "Unknown COSE type '%s'", devices[i].coseType); 636 goto out; 637 } 638 639 if (cfg->userpresence == 1 || strstr(devices[i].attributes, "presence")) 640 user_presence = FIDO_OPT_TRUE; 641 else if (cfg->userpresence == 0) 642 user_presence = FIDO_OPT_FALSE; 643 else 644 user_presence = FIDO_OPT_OMIT; 645 646 if (cfg->userverification == 1 || 647 strstr(devices[i].attributes, "verification")) 648 user_verification = FIDO_OPT_TRUE; 649 else if (cfg->userverification == 0) 650 user_verification = FIDO_OPT_FALSE; 651 else 652 user_verification = FIDO_OPT_OMIT; 653 654 if (cfg->pinverification == 1 || strstr(devices[i].attributes, "pin")) { 655 pin_verification = FIDO_OPT_TRUE; 656 user_verification = FIDO_OPT_TRUE; 657 } else if (cfg->pinverification == 0) 658 pin_verification = FIDO_OPT_FALSE; 659 else 660 pin_verification = FIDO_OPT_OMIT; 661 662 r = fido_assert_set_up(assert, FIDO_OPT_FALSE); 663 if (r != FIDO_OK) { 664 if (cfg->debug) 665 D(cfg->debug_file, "Failed to set UP"); 666 goto out; 667 } 668 669 r = fido_assert_set_uv(assert, FIDO_OPT_OMIT); 670 if (r != FIDO_OK) { 671 if (cfg->debug) 672 D(cfg->debug_file, "Failed to set UV"); 673 goto out; 674 } 675 676 if (!random_bytes(challenge, sizeof(challenge))) { 677 if (cfg->debug) 678 D(cfg->debug_file, "Failed to generate challenge"); 679 goto out; 680 } 681 682 if (cfg->debug) { 683 char *b64_challenge; 684 if (!b64_encode(challenge, sizeof(challenge), &b64_challenge)) { 685 D(cfg->debug_file, "Failed to encode challenge"); 686 } else { 687 D(cfg->debug_file, "Challenge: %s", b64_challenge); 688 free(b64_challenge); 689 } 690 } 691 692 r = fido_assert_set_clientdata_hash(assert, challenge, sizeof(challenge)); 693 if (r != FIDO_OK) { 694 if (cfg->debug) 695 D(cfg->debug_file, "Unable to set challenge: %s( %d)", fido_strerr(r), 696 r); 697 goto out; 698 } 699 700 if (get_authenticators(cfg, devlist, ndevs, assert, kh, authlist)) { 701 for (size_t j = 0; authlist[j] != NULL; j++) { 702 r = fido_assert_set_up(assert, user_presence); 703 if (r != FIDO_OK) { 704 if (cfg->debug) 705 D(cfg->debug_file, "Failed to reset UP"); 706 goto out; 707 } 708 709 r = fido_assert_set_uv(assert, user_verification); 710 if (r != FIDO_OK) { 711 if (cfg->debug) 712 D(cfg->debug_file, "Failed to reset UV"); 713 goto out; 714 } 715 716 if (!random_bytes(challenge, sizeof(challenge))) { 717 if (cfg->debug) 718 D(cfg->debug_file, "Failed to regenerate challenge"); 719 goto out; 720 } 721 722 r = 723 fido_assert_set_clientdata_hash(assert, challenge, sizeof(challenge)); 724 if (r != FIDO_OK) { 725 if (cfg->debug) 726 D(cfg->debug_file, "Unable to reset challenge: %s( %d)", 727 fido_strerr(r), r); 728 goto out; 729 } 730 731 if (pin_verification == FIDO_OPT_TRUE) 732 pin = converse(pamh, PAM_PROMPT_ECHO_OFF, "Please enter the PIN: "); 733 if (user_presence == FIDO_OPT_TRUE || 734 user_verification == FIDO_OPT_TRUE) { 735 if (cfg->manual == 0 && cfg->cue && !cued) { 736 cued = 1; 737 converse(pamh, PAM_TEXT_INFO, 738 cfg->cue_prompt != NULL ? cfg->cue_prompt : DEFAULT_CUE); 739 } 740 } 741 r = fido_dev_get_assert(authlist[j], assert, pin); 742 if (pin) { 743 explicit_bzero(pin, strlen(pin)); 744 free(pin); 745 pin = NULL; 746 } 747 if (r == FIDO_OK) { 748 r = fido_assert_verify(assert, 0, cose_type, 749 cose_type == COSE_ES256 750 ? (const void *) es256_pk 751 : (const void *) rs256_pk); 752 if (r == FIDO_OK) { 753 retval = 1; 754 goto out; 755 } 756 } 757 } 758 } else { 759 if (cfg->debug) 760 D(cfg->debug_file, "Device for this keyhandle is not present."); 761 } 762 763 i++; 764 765 fido_dev_info_free(&devlist, ndevs); 766 767 devlist = fido_dev_info_new(64); 768 if (!devlist) { 769 if (cfg->debug) 770 D(cfg->debug_file, "Unable to allocate devlist"); 771 goto out; 772 } 773 774 r = fido_dev_info_manifest(devlist, 64, &ndevs); 775 if (r != FIDO_OK) { 776 if (cfg->debug) 777 D(cfg->debug_file, "Unable to discover device(s), %s (%d)", 778 fido_strerr(r), r); 779 goto out; 780 } 781 782 if (ndevs > ndevs_prev) { 783 if (cfg->debug) 784 D(cfg->debug_file, 785 "Devices max_index has changed: %zu (was %zu). Starting over", ndevs, 786 ndevs_prev); 787 ndevs_prev = ndevs; 788 i = 0; 789 } 790 791 free(kh); 792 free(pk); 793 794 kh = NULL; 795 pk = NULL; 796 797 for (size_t j = 0; authlist[j] != NULL; j++) { 798 fido_dev_close(authlist[j]); 799 fido_dev_free(&authlist[j]); 800 } 801 802 fido_assert_free(&assert); 803 } 804 805 out: 806 es256_pk_free(&es256_pk); 807 rs256_pk_free(&rs256_pk); 808 fido_assert_free(&assert); 809 fido_dev_info_free(&devlist, ndevs); 810 811 if (authlist) { 812 for (size_t j = 0; authlist[j] != NULL; j++) { 813 fido_dev_close(authlist[j]); 814 fido_dev_free(&authlist[j]); 815 } 816 free(authlist); 817 } 818 819 free(kh); 820 free(pk); 821 822 return retval; 823 } 824 825 #define MAX_PROMPT_LEN (1024) 826 827 int do_manual_authentication(const cfg_t *cfg, const device_t *devices, 828 const unsigned n_devs, pam_handle_t *pamh) { 829 fido_assert_t *assert[n_devs]; 830 es256_pk_t *es256_pk[n_devs]; 831 rs256_pk_t *rs256_pk[n_devs]; 832 unsigned char challenge[32]; 833 unsigned char *kh = NULL; 834 unsigned char *pk = NULL; 835 unsigned char *authdata = NULL; 836 unsigned char *sig = NULL; 837 char *b64_challenge = NULL; 838 char *b64_cdh = NULL; 839 char *b64_rpid = NULL; 840 char *b64_authdata = NULL; 841 char *b64_sig = NULL; 842 char prompt[MAX_PROMPT_LEN]; 843 char buf[MAX_PROMPT_LEN]; 844 size_t kh_len; 845 size_t pk_len; 846 size_t authdata_len; 847 size_t sig_len; 848 int cose_type[n_devs]; 849 int retval = -2; 850 int n; 851 int r; 852 unsigned i = 0; 853 bool user_presence = false; 854 bool user_verification = false; 855 856 memset(assert, 0, sizeof(assert)); 857 memset(es256_pk, 0, sizeof(es256_pk)); 858 memset(rs256_pk, 0, sizeof(rs256_pk)); 859 860 fido_init(cfg->debug ? FIDO_DEBUG : 0); 861 862 for (i = 0; i < n_devs; ++i) { 863 864 assert[i] = fido_assert_new(); 865 if (!assert[i]) { 866 if (cfg->debug) 867 D(cfg->debug_file, "Unable to allocate assertion %u", i); 868 goto out; 869 } 870 871 r = fido_assert_set_rp(assert[i], cfg->origin); 872 if (r != FIDO_OK) { 873 if (cfg->debug) 874 D(cfg->debug_file, "Unable to set origin: %s (%d)", fido_strerr(r), r); 875 goto out; 876 } 877 878 if (strstr(devices[i].attributes, "presence")) 879 user_presence = true; 880 if (strstr(devices[i].attributes, "verification")) 881 user_verification = true; 882 883 r = fido_assert_set_up(assert[i], user_presence); 884 if (r != FIDO_OK) { 885 if (cfg->debug) 886 D(cfg->debug_file, "Unable to set UP: %s (%d)", fido_strerr(r), r); 887 goto out; 888 } 889 890 r = fido_assert_set_uv(assert[i], user_verification); 891 if (r != FIDO_OK) { 892 if (cfg->debug) 893 D(cfg->debug_file, "Unable to set UV: %s (%d)", fido_strerr(r), r); 894 goto out; 895 } 896 897 if (cfg->debug) 898 D(cfg->debug_file, "Attempting authentication with device number %d", 899 i + 1); 900 901 if (!strcmp(devices[i].keyHandle, "*")) { 902 if (cfg->debug) 903 D(cfg->debug_file, "Credential is resident"); 904 } else { 905 if (!b64_decode(devices[i].keyHandle, (void **) &kh, &kh_len)) { 906 if (cfg->debug) 907 D(cfg->debug_file, "Failed to decode key handle"); 908 goto out; 909 } 910 911 r = fido_assert_allow_cred(assert[i], kh, kh_len); 912 if (r != FIDO_OK) { 913 if (cfg->debug) 914 D(cfg->debug_file, "Unable to set keyHandle: %s (%d)", fido_strerr(r), 915 r); 916 goto out; 917 } 918 919 free(kh); 920 kh = NULL; 921 } 922 923 if (devices[i].old_format) { 924 if (!hex_decode(devices[i].publicKey, &pk, &pk_len)) { 925 if (cfg->debug) 926 D(cfg->debug_file, "Failed to decode public key"); 927 goto out; 928 } 929 } else { 930 if (!b64_decode(devices[i].publicKey, (void **) &pk, &pk_len)) { 931 if (cfg->debug) 932 D(cfg->debug_file, "Failed to decode public key"); 933 goto out; 934 } 935 } 936 937 if (!strcmp(devices[i].coseType, "es256")) { 938 es256_pk[i] = es256_pk_new(); 939 if (!es256_pk[i]) { 940 if (cfg->debug) 941 D(cfg->debug_file, "Unable to allocate key %u", i); 942 goto out; 943 } 944 945 if (es256_pk_from_ptr(es256_pk[i], pk, pk_len) != FIDO_OK) { 946 if (cfg->debug) 947 D(cfg->debug_file, "Failed to convert public key"); 948 goto out; 949 } 950 951 cose_type[i] = COSE_ES256; 952 } else { 953 rs256_pk[i] = rs256_pk_new(); 954 if (!rs256_pk[i]) { 955 if (cfg->debug) 956 D(cfg->debug_file, "Unable to allocate key %u", i); 957 goto out; 958 } 959 960 if (rs256_pk_from_ptr(rs256_pk[i], pk, pk_len) != FIDO_OK) { 961 if (cfg->debug) 962 D(cfg->debug_file, "Failed to convert public key"); 963 goto out; 964 } 965 966 cose_type[i] = COSE_RS256; 967 } 968 969 free(pk); 970 pk = NULL; 971 972 if (!random_bytes(challenge, sizeof(challenge))) { 973 if (cfg->debug) 974 D(cfg->debug_file, "Failed to generate challenge"); 975 goto out; 976 } 977 978 r = 979 fido_assert_set_clientdata_hash(assert[i], challenge, sizeof(challenge)); 980 if (r != FIDO_OK) { 981 if (cfg->debug) 982 D(cfg->debug_file, "Failed to set challenge"); 983 goto out; 984 } 985 986 if (!b64_encode(challenge, sizeof(challenge), &b64_challenge)) { 987 if (cfg->debug) 988 D(cfg->debug_file, "Failed to encode challenge"); 989 goto out; 990 } 991 992 if (cfg->debug) 993 D(cfg->debug_file, "Challenge: %s", b64_challenge); 994 995 n = snprintf(prompt, sizeof(prompt), "Challenge #%d:", i + 1); 996 if (n <= 0 || (size_t) n >= sizeof(prompt)) { 997 if (cfg->debug) 998 D(cfg->debug_file, "Failed to print challenge prompt"); 999 goto out; 1000 } 1001 1002 converse(pamh, PAM_TEXT_INFO, prompt); 1003 1004 n = snprintf(buf, sizeof(buf), "%s\n%s\n%s", b64_challenge, cfg->origin, 1005 devices[i].keyHandle); 1006 if (n <= 0 || (size_t) n >= sizeof(buf)) { 1007 if (cfg->debug) 1008 D(cfg->debug_file, "Failed to print fido2-assert input string"); 1009 goto out; 1010 } 1011 1012 converse(pamh, PAM_TEXT_INFO, buf); 1013 1014 free(b64_challenge); 1015 b64_challenge = NULL; 1016 } 1017 1018 converse(pamh, PAM_TEXT_INFO, 1019 "Please pass the challenge(s) above to fido2-assert, and " 1020 "paste the results in the prompt below."); 1021 1022 retval = -1; 1023 1024 for (i = 0; i < n_devs; ++i) { 1025 n = snprintf(prompt, sizeof(prompt), "Response #%d: ", i + 1); 1026 if (n <= 0 || (size_t) n >= sizeof(prompt)) { 1027 if (cfg->debug) 1028 D(cfg->debug_file, "Failed to print response prompt"); 1029 goto out; 1030 } 1031 1032 b64_cdh = converse(pamh, PAM_PROMPT_ECHO_ON, prompt); 1033 b64_rpid = converse(pamh, PAM_PROMPT_ECHO_ON, prompt); 1034 b64_authdata = converse(pamh, PAM_PROMPT_ECHO_ON, prompt); 1035 b64_sig = converse(pamh, PAM_PROMPT_ECHO_ON, prompt); 1036 1037 if (!b64_decode(b64_authdata, (void **) &authdata, &authdata_len)) { 1038 if (cfg->debug) 1039 D(cfg->debug_file, "Failed to decode authenticator data"); 1040 goto out; 1041 } 1042 1043 if (!b64_decode(b64_sig, (void **) &sig, &sig_len)) { 1044 if (cfg->debug) 1045 D(cfg->debug_file, "Failed to decode signature"); 1046 goto out; 1047 } 1048 1049 free(b64_cdh); 1050 free(b64_rpid); 1051 free(b64_authdata); 1052 free(b64_sig); 1053 1054 b64_cdh = NULL; 1055 b64_rpid = NULL; 1056 b64_authdata = NULL; 1057 b64_sig = NULL; 1058 1059 r = fido_assert_set_count(assert[i], 1); 1060 if (r != FIDO_OK) { 1061 if (cfg->debug) 1062 D(cfg->debug_file, "Failed to set signature count of assertion %u", i); 1063 goto out; 1064 } 1065 1066 r = fido_assert_set_authdata(assert[i], 0, authdata, authdata_len); 1067 if (r != FIDO_OK) { 1068 if (cfg->debug) 1069 D(cfg->debug_file, "Failed to set authdata of assertion %u", i); 1070 goto out; 1071 } 1072 1073 r = fido_assert_set_sig(assert[i], 0, sig, sig_len); 1074 if (r != FIDO_OK) { 1075 if (cfg->debug) 1076 D(cfg->debug_file, "Failed to set signature of assertion %u", i); 1077 goto out; 1078 } 1079 1080 free(authdata); 1081 free(sig); 1082 1083 authdata = NULL; 1084 sig = NULL; 1085 1086 if (cose_type[i] == COSE_ES256) 1087 r = fido_assert_verify(assert[i], 0, COSE_ES256, es256_pk[i]); 1088 else 1089 r = fido_assert_verify(assert[i], 0, COSE_RS256, rs256_pk[i]); 1090 1091 if (r == FIDO_OK) { 1092 retval = 1; 1093 break; 1094 } 1095 } 1096 1097 out: 1098 for (i = 0; i < n_devs; i++) { 1099 fido_assert_free(&assert[i]); 1100 es256_pk_free(&es256_pk[i]); 1101 rs256_pk_free(&rs256_pk[i]); 1102 } 1103 1104 free(kh); 1105 free(pk); 1106 free(b64_challenge); 1107 free(b64_cdh); 1108 free(b64_rpid); 1109 free(b64_authdata); 1110 free(b64_sig); 1111 free(authdata); 1112 free(sig); 1113 1114 return retval; 1115 } 1116 1117 static int _converse(pam_handle_t *pamh, int nargs, 1118 const struct pam_message **message, 1119 struct pam_response **response) { 1120 struct pam_conv *conv; 1121 int retval; 1122 1123 retval = pam_get_item(pamh, PAM_CONV, (void *) &conv); 1124 1125 if (retval != PAM_SUCCESS) { 1126 return retval; 1127 } 1128 1129 return conv->conv(nargs, message, response, conv->appdata_ptr); 1130 } 1131 1132 char *converse(pam_handle_t *pamh, int echocode, const char *prompt) { 1133 const struct pam_message msg = {.msg_style = echocode, 1134 .msg = (char *)(uintptr_t)prompt}; 1135 const struct pam_message *msgs = &msg; 1136 struct pam_response *resp = NULL; 1137 int retval = _converse(pamh, 1, &msgs, &resp); 1138 char *ret = NULL; 1139 1140 if (retval != PAM_SUCCESS || resp == NULL || resp->resp == NULL || 1141 *resp->resp == '\000') { 1142 1143 if (retval == PAM_SUCCESS && resp && resp->resp) { 1144 ret = resp->resp; 1145 } 1146 } else { 1147 ret = resp->resp; 1148 } 1149 1150 // Deallocate temporary storage. 1151 if (resp) { 1152 if (!ret) { 1153 free(resp->resp); 1154 } 1155 free(resp); 1156 } 1157 1158 return ret; 1159 } 1160 1161 #if defined(PAM_DEBUG) 1162 void _debug(FILE *debug_file, const char *file, int line, const char *func, 1163 const char *fmt, ...) { 1164 va_list ap; 1165 va_start(ap, fmt); 1166 #ifdef LOG_DEBUG 1167 if (debug_file == (FILE *) -1) { 1168 syslog(LOG_AUTHPRIV | LOG_DEBUG, DEBUG_STR, file, line, func); 1169 vsyslog(LOG_AUTHPRIV | LOG_DEBUG, fmt, ap); 1170 } else { 1171 fprintf(debug_file, DEBUG_STR, file, line, func); 1172 vfprintf(debug_file, fmt, ap); 1173 fprintf(debug_file, "\n"); 1174 } 1175 #else /* Windows, MAC */ 1176 fprintf(debug_file, DEBUG_STR, file, line, func); 1177 vfprintf(debug_file, fmt, ap); 1178 fprintf(debug_file, "\n"); 1179 #endif /* __linux__ */ 1180 va_end(ap); 1181 } 1182 #endif /* PAM_DEBUG */ 1183 1184 #ifndef RANDOM_DEV 1185 #define RANDOM_DEV "/dev/urandom" 1186 #endif 1187 1188 int random_bytes(void *buf, size_t cnt) { 1189 int fd; 1190 ssize_t n; 1191 1192 fd = open(RANDOM_DEV, O_RDONLY); 1193 if (fd < 0) 1194 return (0); 1195 1196 n = read(fd, buf, cnt); 1197 close(fd); 1198 if (n < 0 || (size_t) n != cnt) 1199 return (0); 1200 1201 return (1); 1202 } 1203