1 /* 2 * Copyright (C) 2014-2022 Yubico AB - See COPYING 3 */ 4 5 #include <fido.h> 6 #include <fido/es256.h> 7 #include <fido/rs256.h> 8 #include <fido/eddsa.h> 9 10 #include <openssl/ec.h> 11 #include <openssl/obj_mac.h> 12 13 #include <inttypes.h> 14 #include <limits.h> 15 #include <stdlib.h> 16 #include <fcntl.h> 17 #include <sys/stat.h> 18 #include <pwd.h> 19 #include <errno.h> 20 #include <unistd.h> 21 #include <string.h> 22 #include <arpa/inet.h> 23 24 #include "b64.h" 25 #include "debug.h" 26 #include "util.h" 27 28 #define SSH_MAX_SIZE 8192 29 #define SSH_HEADER "-----BEGIN OPENSSH PRIVATE KEY-----\n" 30 #define SSH_HEADER_LEN (sizeof(SSH_HEADER) - 1) 31 #define SSH_TRAILER "-----END OPENSSH PRIVATE KEY-----\n" 32 #define SSH_TRAILER_LEN (sizeof(SSH_TRAILER) - 1) 33 #define SSH_AUTH_MAGIC "openssh-key-v1" 34 #define SSH_AUTH_MAGIC_LEN (sizeof(SSH_AUTH_MAGIC)) // AUTH_MAGIC includes \0 35 #define SSH_ES256 "sk-ecdsa-sha2-nistp256 (at) openssh.com" 36 #define SSH_ES256_LEN (sizeof(SSH_ES256) - 1) 37 #define SSH_ES256_POINT_LEN 65 38 #define SSH_P256_NAME "nistp256" 39 #define SSH_P256_NAME_LEN (sizeof(SSH_P256_NAME) - 1) 40 #define SSH_EDDSA "sk-ssh-ed25519 (at) openssh.com" 41 #define SSH_EDDSA_LEN (sizeof(SSH_EDDSA) - 1) 42 #define SSH_EDDSA_POINT_LEN 32 43 #define SSH_SK_USER_PRESENCE_REQD 0x01 44 #define SSH_SK_USER_VERIFICATION_REQD 0x04 45 #define SSH_SK_RESIDENT_KEY 0x20 46 47 struct opts { 48 fido_opt_t up; 49 fido_opt_t uv; 50 fido_opt_t pin; 51 }; 52 53 struct pk { 54 void *ptr; 55 int type; 56 }; 57 58 static int hex_decode(const char *ascii_hex, unsigned char **blob, 59 size_t *blob_len) { 60 *blob = NULL; 61 *blob_len = 0; 62 63 if (ascii_hex == NULL || (strlen(ascii_hex) % 2) != 0) 64 return (0); 65 66 *blob_len = strlen(ascii_hex) / 2; 67 *blob = calloc(1, *blob_len); 68 if (*blob == NULL) 69 return (0); 70 71 for (size_t i = 0; i < *blob_len; i++) { 72 unsigned int c; 73 int n = -1; 74 int r = sscanf(ascii_hex, "%02x%n", &c, &n); 75 if (r != 1 || n != 2 || c > UCHAR_MAX) { 76 free(*blob); 77 *blob = NULL; 78 *blob_len = 0; 79 return (0); 80 } 81 (*blob)[i] = (unsigned char) c; 82 ascii_hex += n; 83 } 84 85 return (1); 86 } 87 88 static char *normal_b64(const char *websafe_b64) { 89 char *b64; 90 char *p; 91 size_t n; 92 93 n = strlen(websafe_b64); 94 if (n > SIZE_MAX - 3) 95 return (NULL); 96 97 b64 = calloc(1, n + 3); 98 if (b64 == NULL) 99 return (NULL); 100 101 memcpy(b64, websafe_b64, n); 102 p = b64; 103 104 while ((p = strpbrk(p, "-_")) != NULL) { 105 switch (*p) { 106 case '-': 107 *p++ = '+'; 108 break; 109 case '_': 110 *p++ = '/'; 111 break; 112 } 113 } 114 115 switch (n % 4) { 116 case 1: 117 b64[n] = '='; 118 break; 119 case 2: 120 case 3: 121 b64[n] = '='; 122 b64[n + 1] = '='; 123 break; 124 } 125 126 return (b64); 127 } 128 129 static int translate_old_format_pubkey(es256_pk_t *es256_pk, 130 const unsigned char *pk, size_t pk_len) { 131 EC_KEY *ec = NULL; 132 EC_POINT *q = NULL; 133 const EC_GROUP *g = NULL; 134 int r = FIDO_ERR_INTERNAL; 135 136 if (es256_pk == NULL) 137 goto fail; 138 139 if ((ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)) == NULL || 140 (g = EC_KEY_get0_group(ec)) == NULL) 141 goto fail; 142 143 if ((q = EC_POINT_new(g)) == NULL || 144 !EC_POINT_oct2point(g, q, pk, pk_len, NULL) || 145 !EC_KEY_set_public_key(ec, q)) 146 goto fail; 147 148 r = es256_pk_from_EC_KEY(es256_pk, ec); 149 150 fail: 151 if (ec != NULL) 152 EC_KEY_free(ec); 153 if (q != NULL) 154 EC_POINT_free(q); 155 156 return r; 157 } 158 159 static int is_resident(const char *kh) { return strcmp(kh, "*") == 0; } 160 161 static void reset_device(device_t *device) { 162 free(device->keyHandle); 163 free(device->publicKey); 164 free(device->coseType); 165 free(device->attributes); 166 memset(device, 0, sizeof(*device)); 167 } 168 169 static int parse_native_credential(const cfg_t *cfg, char *s, device_t *cred) { 170 const char *delim = ","; 171 const char *kh, *pk, *type, *attr; 172 char *saveptr = NULL; 173 174 memset(cred, 0, sizeof(*cred)); 175 176 if ((kh = strtok_r(s, delim, &saveptr)) == NULL) { 177 debug_dbg(cfg, "Missing key handle"); 178 goto fail; 179 } 180 181 if ((pk = strtok_r(NULL, delim, &saveptr)) == NULL) { 182 debug_dbg(cfg, "Missing public key"); 183 goto fail; 184 } 185 186 if ((type = strtok_r(NULL, delim, &saveptr)) == NULL) { 187 debug_dbg(cfg, "Old format, assume es256 and +presence"); 188 cred->old_format = 1; 189 type = "es256"; 190 attr = "+presence"; 191 } else if ((attr = strtok_r(NULL, delim, &saveptr)) == NULL) { 192 debug_dbg(cfg, "Empty attributes"); 193 attr = ""; 194 } 195 196 cred->keyHandle = cred->old_format ? normal_b64(kh) : strdup(kh); 197 if (cred->keyHandle == NULL || (cred->publicKey = strdup(pk)) == NULL || 198 (cred->coseType = strdup(type)) == NULL || 199 (cred->attributes = strdup(attr)) == NULL) { 200 debug_dbg(cfg, "Unable to allocate memory for credential components"); 201 goto fail; 202 } 203 204 return 1; 205 206 fail: 207 reset_device(cred); 208 return 0; 209 } 210 211 static int parse_native_format(const cfg_t *cfg, const char *username, 212 FILE *opwfile, device_t *devices, 213 unsigned *n_devs) { 214 215 char *s_user, *s_credential; 216 char *buf = NULL; 217 size_t bufsiz = 0; 218 ssize_t len; 219 unsigned i; 220 int r = 0; 221 222 while ((len = getline(&buf, &bufsiz, opwfile)) != -1) { 223 char *saveptr = NULL; 224 if (len > 0 && buf[len - 1] == '\n') 225 buf[len - 1] = '\0'; 226 227 debug_dbg(cfg, "Read %zu bytes", len); 228 229 s_user = strtok_r(buf, ":", &saveptr); 230 if (s_user && strcmp(username, s_user) == 0) { 231 debug_dbg(cfg, "Matched user: %s", s_user); 232 233 // only keep last line for this user 234 for (i = 0; i < *n_devs; i++) { 235 reset_device(&devices[i]); 236 } 237 *n_devs = 0; 238 239 i = 0; 240 while ((s_credential = strtok_r(NULL, ":", &saveptr))) { 241 if ((*n_devs)++ > cfg->max_devs - 1) { 242 *n_devs = cfg->max_devs; 243 debug_dbg(cfg, 244 "Found more than %d devices, ignoring the remaining ones", 245 cfg->max_devs); 246 break; 247 } 248 249 if (!parse_native_credential(cfg, s_credential, &devices[i])) { 250 debug_dbg(cfg, "Failed to parse credential"); 251 goto fail; 252 } 253 254 debug_dbg(cfg, "KeyHandle for device number %u: %s", i + 1, 255 devices[i].keyHandle); 256 debug_dbg(cfg, "publicKey for device number %u: %s", i + 1, 257 devices[i].publicKey); 258 debug_dbg(cfg, "COSE type for device number %u: %s", i + 1, 259 devices[i].coseType); 260 debug_dbg(cfg, "Attributes for device number %u: %s", i + 1, 261 devices[i].attributes); 262 i++; 263 } 264 } 265 } 266 267 if (!feof(opwfile)) { 268 debug_dbg(cfg, "authfile parsing ended before eof (%d)", errno); 269 goto fail; 270 } 271 272 r = 1; 273 fail: 274 free(buf); 275 return r; 276 } 277 278 static int load_ssh_key(const cfg_t *cfg, char **out, FILE *opwfile, 279 size_t opwfile_size) { 280 size_t buf_size; 281 char *buf = NULL; 282 char *cp = NULL; 283 int r = 0; 284 int ch; 285 286 *out = NULL; 287 288 if (opwfile_size < SSH_HEADER_LEN + SSH_TRAILER_LEN) { 289 debug_dbg(cfg, "Malformed SSH key (length)"); 290 goto fail; 291 } 292 293 buf_size = opwfile_size > SSH_MAX_SIZE ? SSH_MAX_SIZE : opwfile_size; 294 if ((cp = buf = calloc(1, buf_size)) == NULL) { 295 debug_dbg(cfg, "Failed to allocate buffer for SSH key"); 296 goto fail; 297 } 298 299 // NOTE(adma): +1 for \0 300 if (fgets(buf, (int)(SSH_HEADER_LEN + 1), opwfile) == NULL || 301 strlen(buf) != SSH_HEADER_LEN || 302 strncmp(buf, SSH_HEADER, SSH_HEADER_LEN) != 0) { 303 debug_dbg(cfg, "Malformed SSH key (header)"); 304 goto fail; 305 } 306 307 while (opwfile_size > 0 && buf_size > 1) { 308 ch = fgetc(opwfile); 309 if (ch == EOF) { 310 debug_dbg(cfg, "Unexpected authfile termination"); 311 goto fail; 312 } 313 314 opwfile_size--; 315 316 if (ch != '\n' && ch != '\r') { 317 *cp = (char) ch; 318 buf_size--; 319 if (ch == '-') { 320 // NOTE(adma): no +1 here since we already read one '-' 321 if (buf_size < SSH_TRAILER_LEN || 322 fgets(cp + 1, (int)SSH_TRAILER_LEN, opwfile) == NULL || 323 strlen(cp) != SSH_TRAILER_LEN || 324 strncmp(cp, SSH_TRAILER, SSH_TRAILER_LEN) != 0) { 325 debug_dbg(cfg, "Malformed SSH key (trailer)"); 326 goto fail; 327 } 328 329 r = 1; 330 *(cp) = '\0'; 331 break; 332 } else { 333 cp++; 334 } 335 } 336 } 337 338 fail: 339 if (r != 1) { 340 free(buf); 341 buf = NULL; 342 } 343 344 *out = buf; 345 346 return r; 347 } 348 349 static int ssh_get(const unsigned char **buf, size_t *size, unsigned char *dst, 350 size_t len) { 351 if (*size < len) 352 return 0; 353 if (dst != NULL) 354 memcpy(dst, *buf, len); 355 *buf += len; 356 *size -= len; 357 return 1; 358 } 359 360 static int ssh_get_u8(const unsigned char **buf, size_t *size, uint8_t *val) { 361 return ssh_get(buf, size, val, sizeof(*val)); 362 } 363 364 static int ssh_get_u32(const unsigned char **buf, size_t *size, uint32_t *val) { 365 if (!ssh_get(buf, size, (unsigned char *) val, sizeof(*val))) 366 return 0; 367 if (val != NULL) 368 *val = ntohl(*val); 369 return 1; 370 } 371 372 static int ssh_get_string_ref(const unsigned char **buf, size_t *size, 373 const unsigned char **ref, size_t *lenp) { 374 uint32_t len; 375 376 if (!ssh_get_u32(buf, size, &len)) 377 return 0; 378 if (!ssh_get(buf, size, NULL, len)) 379 return 0; 380 if (ref != NULL) 381 *ref = *buf - len; 382 if (lenp != NULL) 383 *lenp = len; 384 return 1; 385 } 386 387 static int ssh_get_cstring(const unsigned char **buf, size_t *size, char **str, 388 size_t *lenp) { 389 const unsigned char *ref; 390 size_t len; 391 392 if (!ssh_get_string_ref(buf, size, &ref, &len)) 393 return 0; 394 if (str != NULL) { 395 if (len > SIZE_MAX - 1 || (*str = calloc(1, len + 1)) == NULL) 396 return 0; 397 memcpy(*str, ref, len); 398 } 399 if (lenp != NULL) 400 *lenp = len; 401 return 1; 402 } 403 404 static int ssh_log_cstring(const cfg_t *cfg, const unsigned char **buf, 405 size_t *size, const char *name) { 406 char *str = NULL; 407 size_t len; 408 409 (void) name; // silence compiler warnings if PAM_DEBUG disabled 410 411 if (!ssh_get_cstring(buf, size, &str, &len)) { 412 debug_dbg(cfg, "Malformed SSH key (%s)", name); 413 return 0; 414 } 415 debug_dbg(cfg, "%s (%zu) \"%s\"", name, len, str); 416 417 free(str); 418 return 1; 419 } 420 421 static int ssh_get_attrs(const cfg_t *cfg, const unsigned char **buf, 422 size_t *size, char **attrs) { 423 char tmp[32] = {0}; 424 uint8_t flags; 425 int r; 426 427 // flags 428 if (!ssh_get_u8(buf, size, &flags)) { 429 debug_dbg(cfg, "Malformed SSH key (flags)"); 430 return 0; 431 } 432 debug_dbg(cfg, "flags: %02x", flags); 433 434 r = snprintf(tmp, sizeof(tmp), "%s%s", 435 flags & SSH_SK_USER_PRESENCE_REQD ? "+presence" : "", 436 flags & SSH_SK_USER_VERIFICATION_REQD ? "+verification" : ""); 437 if (r < 0 || (size_t) r >= sizeof(tmp)) { 438 debug_dbg(cfg, "Unable to prepare flags"); 439 return 0; 440 } 441 442 if ((*attrs = strdup(tmp)) == NULL) { 443 debug_dbg(cfg, "Unable to allocate attributes"); 444 return 0; 445 } 446 447 return 1; 448 } 449 450 static int ssh_get_pubkey(const cfg_t *cfg, const unsigned char **buf, 451 size_t *size, char **type_p, char **pubkey_p) { 452 char *ssh_type = NULL; 453 char *ssh_curve = NULL; 454 const unsigned char *blob; 455 size_t len; 456 int type; 457 size_t point_len; 458 int ok = 0; 459 460 *type_p = NULL; 461 *pubkey_p = NULL; 462 463 // key type 464 if (!ssh_get_cstring(buf, size, &ssh_type, &len)) { 465 debug_dbg(cfg, "Malformed SSH key (keytype)"); 466 goto err; 467 } 468 469 if (len == SSH_ES256_LEN && memcmp(ssh_type, SSH_ES256, SSH_ES256_LEN) == 0) { 470 type = COSE_ES256; 471 point_len = SSH_ES256_POINT_LEN; 472 } else if (len == SSH_EDDSA_LEN && 473 memcmp(ssh_type, SSH_EDDSA, SSH_EDDSA_LEN) == 0) { 474 type = COSE_EDDSA; 475 point_len = SSH_EDDSA_POINT_LEN; 476 } else { 477 debug_dbg(cfg, "Unknown key type %s", ssh_type); 478 goto err; 479 } 480 481 debug_dbg(cfg, "keytype (%zu) \"%s\"", len, ssh_type); 482 483 if (type == COSE_ES256) { 484 // curve name 485 if (!ssh_get_cstring(buf, size, &ssh_curve, &len)) { 486 debug_dbg(cfg, "Malformed SSH key (curvename)"); 487 goto err; 488 } 489 490 if (len == SSH_P256_NAME_LEN && 491 memcmp(ssh_curve, SSH_P256_NAME, SSH_P256_NAME_LEN) == 0) { 492 debug_dbg(cfg, "curvename (%zu) \"%s\"", len, ssh_curve); 493 } else { 494 debug_dbg(cfg, "Unknown curve %s", ssh_curve); 495 goto err; 496 } 497 } 498 499 // point 500 if (!ssh_get_string_ref(buf, size, &blob, &len)) { 501 debug_dbg(cfg, "Malformed SSH key (point)"); 502 goto err; 503 } 504 505 if (len != point_len) { 506 debug_dbg(cfg, "Invalid point length, should be %zu, found %zu", point_len, 507 len); 508 goto err; 509 } 510 511 if (type == COSE_ES256) { 512 // Skip the initial '04' 513 if (len < 1) { 514 debug_dbg(cfg, "Failed to skip initial '04'"); 515 goto err; 516 } 517 blob++; 518 len--; 519 } 520 521 if (!b64_encode(blob, len, pubkey_p)) { 522 debug_dbg(cfg, "Unable to allocate public key"); 523 goto err; 524 } 525 526 if ((*type_p = strdup(cose_string(type))) == NULL) { 527 debug_dbg(cfg, "Unable to allocate COSE type"); 528 goto err; 529 } 530 531 ok = 1; 532 err: 533 if (!ok) { 534 free(*type_p); 535 free(*pubkey_p); 536 *type_p = NULL; 537 *pubkey_p = NULL; 538 } 539 free(ssh_type); 540 free(ssh_curve); 541 542 return ok; 543 } 544 545 static int parse_ssh_format(const cfg_t *cfg, FILE *opwfile, 546 size_t opwfile_size, device_t *devices, 547 unsigned *n_devs) { 548 char *b64 = NULL; 549 const unsigned char *decoded; 550 unsigned char *decoded_initial = NULL; 551 size_t decoded_len; 552 const unsigned char *blob; 553 uint32_t check1, check2, tmp; 554 size_t len; 555 int r = 0; 556 557 // The logic below is inspired by 558 // how ssh parses its own keys. See sshkey.c 559 reset_device(&devices[0]); 560 *n_devs = 0; 561 562 if (!load_ssh_key(cfg, &b64, opwfile, opwfile_size) || 563 !b64_decode(b64, (void **) &decoded_initial, &decoded_len)) { 564 debug_dbg(cfg, "Unable to decode credential"); 565 goto out; 566 } 567 568 decoded = decoded_initial; 569 570 // magic 571 if (decoded_len < SSH_AUTH_MAGIC_LEN || 572 memcmp(decoded, SSH_AUTH_MAGIC, SSH_AUTH_MAGIC_LEN) != 0) { 573 debug_dbg(cfg, "Malformed SSH key (magic)"); 574 goto out; 575 } 576 577 decoded += SSH_AUTH_MAGIC_LEN; 578 decoded_len -= SSH_AUTH_MAGIC_LEN; 579 580 if (!ssh_log_cstring(cfg, &decoded, &decoded_len, "ciphername") || 581 !ssh_log_cstring(cfg, &decoded, &decoded_len, "kdfname") || 582 !ssh_log_cstring(cfg, &decoded, &decoded_len, "kdfoptions")) 583 goto out; 584 585 if (!ssh_get_u32(&decoded, &decoded_len, &tmp)) { 586 debug_dbg(cfg, "Malformed SSH key (nkeys)"); 587 goto out; 588 } 589 debug_dbg(cfg, "nkeys: %" PRIu32, tmp); 590 if (tmp != 1) { 591 debug_dbg(cfg, "Multiple keys not supported"); 592 goto out; 593 } 594 595 // public_key (skip) 596 if (!ssh_get_string_ref(&decoded, &decoded_len, NULL, NULL)) { 597 debug_dbg(cfg, "Malformed SSH key (pubkey)"); 598 goto out; 599 } 600 601 // private key (consume length) 602 if (!ssh_get_u32(&decoded, &decoded_len, &tmp) || decoded_len < tmp) { 603 debug_dbg(cfg, "Malformed SSH key (pvtkey length)"); 604 goto out; 605 } 606 607 // check1, check2 608 if (!ssh_get_u32(&decoded, &decoded_len, &check1) || 609 !ssh_get_u32(&decoded, &decoded_len, &check2)) { 610 debug_dbg(cfg, "Malformed SSH key (check1, check2)"); 611 goto out; 612 } 613 614 debug_dbg(cfg, "check1: %" PRIu32, check1); 615 debug_dbg(cfg, "check2: %" PRIu32, check2); 616 617 if (check1 != check2) { 618 debug_dbg(cfg, "Mismatched check values"); 619 goto out; 620 } 621 622 if (!ssh_get_pubkey(cfg, &decoded, &decoded_len, &devices[0].coseType, 623 &devices[0].publicKey) || 624 !ssh_log_cstring(cfg, &decoded, &decoded_len, "application") || 625 !ssh_get_attrs(cfg, &decoded, &decoded_len, &devices[0].attributes)) 626 goto out; 627 628 // keyhandle 629 if (!ssh_get_string_ref(&decoded, &decoded_len, &blob, &len) || 630 !b64_encode(blob, len, &devices[0].keyHandle)) { 631 debug_dbg(cfg, "Malformed SSH key (keyhandle)"); 632 goto out; 633 } 634 635 debug_dbg(cfg, "KeyHandle for device number 1: %s", devices[0].keyHandle); 636 debug_dbg(cfg, "publicKey for device number 1: %s", devices[0].publicKey); 637 debug_dbg(cfg, "COSE type for device number 1: %s", devices[0].coseType); 638 debug_dbg(cfg, "Attributes for device number 1: %s", devices[0].attributes); 639 640 // reserved (skip) 641 if (!ssh_get_string_ref(&decoded, &decoded_len, NULL, NULL)) { 642 debug_dbg(cfg, "Malformed SSH key (reserved)"); 643 goto out; 644 } 645 646 // comment 647 if (!ssh_log_cstring(cfg, &decoded, &decoded_len, "comment")) 648 goto out; 649 650 // padding 651 if (decoded_len >= 255) { 652 debug_dbg(cfg, "Malformed SSH key (padding length)"); 653 goto out; 654 } 655 656 for (int i = 1; (unsigned) i <= decoded_len; i++) { 657 if (decoded[i - 1] != i) { 658 debug_dbg(cfg, "Malformed SSH key (padding)"); 659 goto out; 660 } 661 } 662 663 *n_devs = 1; 664 r = 1; 665 666 out: 667 if (r != 1) { 668 reset_device(&devices[0]); 669 *n_devs = 0; 670 } 671 672 free(decoded_initial); 673 free(b64); 674 675 return r; 676 } 677 678 int get_devices_from_authfile(const cfg_t *cfg, const char *username, 679 device_t *devices, unsigned *n_devs) { 680 681 int r = PAM_AUTHINFO_UNAVAIL; 682 int fd = -1; 683 struct stat st; 684 struct passwd *pw = NULL, pw_s; 685 char buffer[BUFSIZE]; 686 int gpu_ret; 687 FILE *opwfile = NULL; 688 size_t opwfile_size; 689 unsigned i; 690 691 /* Ensure we never return uninitialized count. */ 692 *n_devs = 0; 693 694 fd = open(cfg->auth_file, O_RDONLY | O_CLOEXEC | O_NOCTTY); 695 if (fd < 0) { 696 if (errno == ENOENT && cfg->nouserok) { 697 r = PAM_IGNORE; 698 } 699 debug_dbg(cfg, "Cannot open authentication file: %s", strerror(errno)); 700 goto err; 701 } 702 703 if (fstat(fd, &st) < 0) { 704 debug_dbg(cfg, "Cannot stat authentication file: %s", strerror(errno)); 705 goto err; 706 } 707 708 if (!S_ISREG(st.st_mode)) { 709 debug_dbg(cfg, "Authentication file is not a regular file"); 710 goto err; 711 } 712 713 if ((st.st_mode & (S_IWGRP | S_IWOTH)) != 0) { 714 debug_dbg(cfg, "Authentication file has insecure permissions"); 715 goto err; 716 } 717 718 opwfile_size = (size_t)st.st_size; 719 720 gpu_ret = getpwuid_r(st.st_uid, &pw_s, buffer, sizeof(buffer), &pw); 721 if (gpu_ret != 0 || pw == NULL) { 722 debug_dbg(cfg, "Unable to retrieve credentials for uid %u, (%s)", st.st_uid, 723 strerror(errno)); 724 goto err; 725 } 726 727 if (strcmp(pw->pw_name, username) != 0 && strcmp(pw->pw_name, "root") != 0) { 728 if (strcmp(username, "root") != 0) { 729 debug_dbg(cfg, 730 "The owner of the authentication file is neither %s nor root", 731 username); 732 } else { 733 debug_dbg(cfg, "The owner of the authentication file is not root"); 734 } 735 goto err; 736 } 737 738 opwfile = fdopen(fd, "r"); 739 if (opwfile == NULL) { 740 debug_dbg(cfg, "fdopen: %s", strerror(errno)); 741 goto err; 742 } else { 743 fd = -1; /* fd belongs to opwfile */ 744 } 745 746 if (cfg->sshformat == 0) { 747 if (parse_native_format(cfg, username, opwfile, devices, n_devs) != 1) { 748 goto err; 749 } 750 } else { 751 if (parse_ssh_format(cfg, opwfile, opwfile_size, devices, n_devs) != 1) { 752 goto err; 753 } 754 } 755 756 debug_dbg(cfg, "Found %d device(s) for user %s", *n_devs, username); 757 r = PAM_SUCCESS; 758 759 err: 760 if (r != PAM_SUCCESS) { 761 for (i = 0; i < *n_devs; i++) { 762 reset_device(&devices[i]); 763 } 764 *n_devs = 0; 765 } else if (*n_devs == 0) { 766 r = cfg->nouserok ? PAM_IGNORE : PAM_USER_UNKNOWN; 767 } 768 769 if (opwfile) 770 fclose(opwfile); 771 772 if (fd != -1) 773 close(fd); 774 775 return r; 776 } 777 778 void free_devices(device_t *devices, const unsigned n_devs) { 779 unsigned i; 780 781 if (!devices) 782 return; 783 784 for (i = 0; i < n_devs; i++) { 785 reset_device(&devices[i]); 786 } 787 788 free(devices); 789 devices = NULL; 790 } 791 792 static int get_authenticators(const cfg_t *cfg, const fido_dev_info_t *devlist, 793 size_t devlist_len, fido_assert_t *assert, 794 const int rk, fido_dev_t **authlist) { 795 const fido_dev_info_t *di = NULL; 796 fido_dev_t *dev = NULL; 797 int r; 798 size_t i; 799 size_t j; 800 801 debug_dbg(cfg, "Working with %zu authenticator(s)", devlist_len); 802 803 for (i = 0, j = 0; i < devlist_len; i++) { 804 debug_dbg(cfg, "Checking whether key exists in authenticator %zu", i); 805 806 di = fido_dev_info_ptr(devlist, i); 807 if (!di) { 808 debug_dbg(cfg, "Unable to get device pointer"); 809 continue; 810 } 811 812 debug_dbg(cfg, "Authenticator path: %s", fido_dev_info_path(di)); 813 814 dev = fido_dev_new(); 815 if (!dev) { 816 debug_dbg(cfg, "Unable to allocate device type"); 817 continue; 818 } 819 820 r = fido_dev_open(dev, fido_dev_info_path(di)); 821 if (r != FIDO_OK) { 822 debug_dbg(cfg, "Failed to open authenticator: %s (%d)", fido_strerr(r), 823 r); 824 fido_dev_free(&dev); 825 continue; 826 } 827 828 if (rk || cfg->nodetect) { 829 /* resident credential or nodetect: try all authenticators */ 830 authlist[j++] = dev; 831 } else { 832 r = fido_dev_get_assert(dev, assert, NULL); 833 if ((!fido_dev_is_fido2(dev) && r == FIDO_ERR_USER_PRESENCE_REQUIRED) || 834 (fido_dev_is_fido2(dev) && r == FIDO_OK)) { 835 authlist[j++] = dev; 836 debug_dbg(cfg, "Found key in authenticator %zu", i); 837 return (1); 838 } 839 debug_dbg(cfg, "Key not found in authenticator %zu", i); 840 841 fido_dev_close(dev); 842 fido_dev_free(&dev); 843 } 844 } 845 846 if (j != 0) 847 return (1); 848 else { 849 debug_dbg(cfg, "Key not found"); 850 return (0); 851 } 852 } 853 854 static void init_opts(struct opts *opts) { 855 opts->up = FIDO_OPT_FALSE; 856 opts->uv = FIDO_OPT_OMIT; 857 opts->pin = FIDO_OPT_FALSE; 858 } 859 860 static void parse_opts(const cfg_t *cfg, const char *attr, struct opts *opts) { 861 if (cfg->userpresence == 1 || strstr(attr, "+presence")) { 862 opts->up = FIDO_OPT_TRUE; 863 } else if (cfg->userpresence == 0) { 864 opts->up = FIDO_OPT_FALSE; 865 } else { 866 opts->up = FIDO_OPT_OMIT; 867 } 868 869 if (cfg->userverification == 1 || strstr(attr, "+verification")) { 870 opts->uv = FIDO_OPT_TRUE; 871 } else if (cfg->userverification == 0) 872 opts->uv = FIDO_OPT_FALSE; 873 else { 874 opts->uv = FIDO_OPT_OMIT; 875 } 876 877 if (cfg->pinverification == 1 || strstr(attr, "+pin")) { 878 opts->pin = FIDO_OPT_TRUE; 879 } else if (cfg->pinverification == 0) { 880 opts->pin = FIDO_OPT_FALSE; 881 } else { 882 opts->pin = FIDO_OPT_OMIT; 883 } 884 } 885 886 static int get_device_opts(fido_dev_t *dev, int *pin, int *uv) { 887 fido_cbor_info_t *info = NULL; 888 char *const *ptr; 889 const bool *val; 890 size_t len; 891 892 *pin = *uv = -1; /* unsupported */ 893 894 if (fido_dev_is_fido2(dev)) { 895 if ((info = fido_cbor_info_new()) == NULL || 896 fido_dev_get_cbor_info(dev, info) != FIDO_OK) { 897 fido_cbor_info_free(&info); 898 return 0; 899 } 900 901 ptr = fido_cbor_info_options_name_ptr(info); 902 val = fido_cbor_info_options_value_ptr(info); 903 len = fido_cbor_info_options_len(info); 904 for (size_t i = 0; i < len; i++) { 905 if (strcmp(ptr[i], "clientPin") == 0) { 906 *pin = val[i]; 907 } else if (strcmp(ptr[i], "uv") == 0) { 908 *uv = val[i]; 909 } 910 } 911 } 912 913 fido_cbor_info_free(&info); 914 return 1; 915 } 916 917 static int match_device_opts(fido_dev_t *dev, struct opts *opts) { 918 int pin, uv; 919 920 /* FIXME: fido_dev_{supports,has}_{pin,uv} (1.7.0) */ 921 if (!get_device_opts(dev, &pin, &uv)) { 922 return -1; 923 } 924 925 if (opts->uv == FIDO_OPT_FALSE && uv < 0) { 926 opts->uv = FIDO_OPT_OMIT; 927 } 928 929 if ((opts->pin == FIDO_OPT_TRUE && pin != 1) || 930 (opts->uv == FIDO_OPT_TRUE && uv != 1)) { 931 return 0; 932 } 933 934 return 1; 935 } 936 937 static int set_opts(const cfg_t *cfg, const struct opts *opts, 938 fido_assert_t *assert) { 939 if (fido_assert_set_up(assert, opts->up) != FIDO_OK) { 940 debug_dbg(cfg, "Failed to set UP"); 941 return 0; 942 } 943 if (fido_assert_set_uv(assert, opts->uv) != FIDO_OK) { 944 debug_dbg(cfg, "Failed to set UV"); 945 return 0; 946 } 947 948 return 1; 949 } 950 951 static int set_cdh(const cfg_t *cfg, fido_assert_t *assert) { 952 unsigned char cdh[32]; 953 int r; 954 955 if (!random_bytes(cdh, sizeof(cdh))) { 956 debug_dbg(cfg, "Failed to generate challenge"); 957 return 0; 958 } 959 960 r = fido_assert_set_clientdata_hash(assert, cdh, sizeof(cdh)); 961 if (r != FIDO_OK) { 962 debug_dbg(cfg, "Unable to set challenge: %s (%d)", fido_strerr(r), r); 963 return 0; 964 } 965 966 return 1; 967 } 968 969 static fido_assert_t *prepare_assert(const cfg_t *cfg, const device_t *device, 970 const struct opts *opts) { 971 fido_assert_t *assert = NULL; 972 unsigned char *buf = NULL; 973 size_t buf_len; 974 int ok = 0; 975 int r; 976 977 if ((assert = fido_assert_new()) == NULL) { 978 debug_dbg(cfg, "Unable to allocate assertion"); 979 goto err; 980 } 981 982 if (device->old_format) 983 r = fido_assert_set_rp(assert, cfg->appid); 984 else 985 r = fido_assert_set_rp(assert, cfg->origin); 986 987 if (r != FIDO_OK) { 988 debug_dbg(cfg, "Unable to set origin: %s (%d)", fido_strerr(r), r); 989 goto err; 990 } 991 992 if (is_resident(device->keyHandle)) { 993 debug_dbg(cfg, "Credential is resident"); 994 } else { 995 debug_dbg(cfg, "Key handle: %s", device->keyHandle); 996 if (!b64_decode(device->keyHandle, (void **) &buf, &buf_len)) { 997 debug_dbg(cfg, "Failed to decode key handle"); 998 goto err; 999 } 1000 1001 r = fido_assert_allow_cred(assert, buf, buf_len); 1002 if (r != FIDO_OK) { 1003 debug_dbg(cfg, "Unable to set keyHandle: %s (%d)", fido_strerr(r), r); 1004 goto err; 1005 } 1006 } 1007 1008 if (!set_opts(cfg, opts, assert)) { 1009 debug_dbg(cfg, "Failed to set assert options"); 1010 goto err; 1011 } 1012 1013 if (!set_cdh(cfg, assert)) { 1014 debug_dbg(cfg, "Failed to set client data hash"); 1015 goto err; 1016 } 1017 1018 ok = 1; 1019 1020 err: 1021 if (!ok) 1022 fido_assert_free(&assert); 1023 1024 free(buf); 1025 1026 return assert; 1027 } 1028 1029 static void reset_pk(struct pk *pk) { 1030 if (pk->type == COSE_ES256) { 1031 es256_pk_free((es256_pk_t **) &pk->ptr); 1032 } else if (pk->type == COSE_RS256) { 1033 rs256_pk_free((rs256_pk_t **) &pk->ptr); 1034 } else if (pk->type == COSE_EDDSA) { 1035 eddsa_pk_free((eddsa_pk_t **) &pk->ptr); 1036 } 1037 memset(pk, 0, sizeof(*pk)); 1038 } 1039 1040 int cose_type(const char *str, int *type) { 1041 if (strcasecmp(str, "es256") == 0) { 1042 *type = COSE_ES256; 1043 } else if (strcasecmp(str, "rs256") == 0) { 1044 *type = COSE_RS256; 1045 } else if (strcasecmp(str, "eddsa") == 0) { 1046 *type = COSE_EDDSA; 1047 } else { 1048 *type = 0; 1049 return 0; 1050 } 1051 1052 return 1; 1053 } 1054 1055 const char *cose_string(int type) { 1056 switch (type) { 1057 case COSE_ES256: 1058 return "es256"; 1059 case COSE_RS256: 1060 return "rs256"; 1061 case COSE_EDDSA: 1062 return "eddsa"; 1063 default: 1064 return "unknown"; 1065 } 1066 } 1067 1068 static int parse_pk(const cfg_t *cfg, int old, const char *type, const char *pk, 1069 struct pk *out) { 1070 unsigned char *buf = NULL; 1071 size_t buf_len; 1072 int ok = 0; 1073 int r; 1074 1075 reset_pk(out); 1076 1077 if (old) { 1078 if (!hex_decode(pk, &buf, &buf_len)) { 1079 debug_dbg(cfg, "Failed to decode public key"); 1080 goto err; 1081 } 1082 } else { 1083 if (!b64_decode(pk, (void **) &buf, &buf_len)) { 1084 debug_dbg(cfg, "Failed to decode public key"); 1085 goto err; 1086 } 1087 } 1088 1089 if (!cose_type(type, &out->type)) { 1090 debug_dbg(cfg, "Unknown COSE type '%s'", type); 1091 goto err; 1092 } 1093 1094 // For backwards compatibility, failure to pack the public key is not 1095 // returned as an error. Instead, it is handled by fido_verify_assert(). 1096 if (out->type == COSE_ES256) { 1097 if ((out->ptr = es256_pk_new()) == NULL) { 1098 debug_dbg(cfg, "Failed to allocate ES256 public key"); 1099 goto err; 1100 } 1101 if (old) { 1102 r = translate_old_format_pubkey(out->ptr, buf, buf_len); 1103 } else { 1104 r = es256_pk_from_ptr(out->ptr, buf, buf_len); 1105 } 1106 if (r != FIDO_OK) { 1107 debug_dbg(cfg, "Failed to convert ES256 public key"); 1108 } 1109 } else if (out->type == COSE_RS256) { 1110 if ((out->ptr = rs256_pk_new()) == NULL) { 1111 debug_dbg(cfg, "Failed to allocate RS256 public key"); 1112 goto err; 1113 } 1114 r = rs256_pk_from_ptr(out->ptr, buf, buf_len); 1115 if (r != FIDO_OK) { 1116 debug_dbg(cfg, "Failed to convert RS256 public key"); 1117 } 1118 } else if (out->type == COSE_EDDSA) { 1119 if ((out->ptr = eddsa_pk_new()) == NULL) { 1120 debug_dbg(cfg, "Failed to allocate EDDSA public key"); 1121 goto err; 1122 } 1123 r = eddsa_pk_from_ptr(out->ptr, buf, buf_len); 1124 if (r != FIDO_OK) { 1125 debug_dbg(cfg, "Failed to convert EDDSA public key"); 1126 } 1127 } else { 1128 debug_dbg(cfg, "COSE type '%s' not handled", type); 1129 goto err; 1130 } 1131 1132 ok = 1; 1133 err: 1134 free(buf); 1135 1136 return ok; 1137 } 1138 1139 int do_authentication(const cfg_t *cfg, const device_t *devices, 1140 const unsigned n_devs, pam_handle_t *pamh) { 1141 fido_assert_t *assert = NULL; 1142 fido_dev_info_t *devlist = NULL; 1143 fido_dev_t **authlist = NULL; 1144 int cued = 0; 1145 int r; 1146 int retval = PAM_AUTH_ERR; 1147 size_t ndevs = 0; 1148 size_t ndevs_prev = 0; 1149 unsigned i = 0; 1150 struct opts opts; 1151 struct pk pk; 1152 char *pin = NULL; 1153 1154 init_opts(&opts); 1155 #ifndef WITH_FUZZING 1156 fido_init(cfg->debug ? FIDO_DEBUG : 0); 1157 #else 1158 fido_init(0); 1159 #endif 1160 memset(&pk, 0, sizeof(pk)); 1161 1162 devlist = fido_dev_info_new(DEVLIST_LEN); 1163 if (!devlist) { 1164 debug_dbg(cfg, "Unable to allocate devlist"); 1165 goto out; 1166 } 1167 1168 r = fido_dev_info_manifest(devlist, DEVLIST_LEN, &ndevs); 1169 if (r != FIDO_OK) { 1170 debug_dbg(cfg, "Unable to discover device(s), %s (%d)", fido_strerr(r), r); 1171 goto out; 1172 } 1173 1174 ndevs_prev = ndevs; 1175 1176 debug_dbg(cfg, "Device max index is %zu", ndevs); 1177 1178 authlist = calloc(DEVLIST_LEN + 1, sizeof(fido_dev_t *)); 1179 if (!authlist) { 1180 debug_dbg(cfg, "Unable to allocate authenticator list"); 1181 goto out; 1182 } 1183 1184 if (cfg->nodetect) 1185 debug_dbg(cfg, "nodetect option specified, suitable key detection will be " 1186 "skipped"); 1187 1188 i = 0; 1189 while (i < n_devs) { 1190 debug_dbg(cfg, "Attempting authentication with device number %d", i + 1); 1191 1192 init_opts(&opts); /* used during authenticator discovery */ 1193 assert = prepare_assert(cfg, &devices[i], &opts); 1194 if (assert == NULL) { 1195 debug_dbg(cfg, "Failed to prepare assert"); 1196 goto out; 1197 } 1198 1199 if (!parse_pk(cfg, devices[i].old_format, devices[i].coseType, 1200 devices[i].publicKey, &pk)) { 1201 debug_dbg(cfg, "Failed to parse public key"); 1202 goto out; 1203 } 1204 1205 if (get_authenticators(cfg, devlist, ndevs, assert, 1206 is_resident(devices[i].keyHandle), authlist)) { 1207 for (size_t j = 0; authlist[j] != NULL; j++) { 1208 /* options used during authentication */ 1209 parse_opts(cfg, devices[i].attributes, &opts); 1210 1211 r = match_device_opts(authlist[j], &opts); 1212 if (r != 1) { 1213 debug_dbg(cfg, "%s, skipping authenticator", 1214 r < 0 ? "Failed to query supported options" 1215 : "Unsupported options"); 1216 continue; 1217 } 1218 1219 if (!set_opts(cfg, &opts, assert)) { 1220 debug_dbg(cfg, "Failed to set assert options"); 1221 goto out; 1222 } 1223 1224 if (!set_cdh(cfg, assert)) { 1225 debug_dbg(cfg, "Failed to reset client data hash"); 1226 goto out; 1227 } 1228 1229 if (opts.pin == FIDO_OPT_TRUE) { 1230 pin = converse(pamh, PAM_PROMPT_ECHO_OFF, "Please enter the PIN: "); 1231 if (pin == NULL) { 1232 debug_dbg(cfg, "converse() returned NULL"); 1233 goto out; 1234 } 1235 } 1236 if (opts.up == FIDO_OPT_TRUE || opts.uv == FIDO_OPT_TRUE) { 1237 if (cfg->manual == 0 && cfg->cue && !cued) { 1238 cued = 1; 1239 converse(pamh, PAM_TEXT_INFO, 1240 cfg->cue_prompt != NULL ? cfg->cue_prompt : DEFAULT_CUE); 1241 } 1242 } 1243 r = fido_dev_get_assert(authlist[j], assert, pin); 1244 if (pin) { 1245 explicit_bzero(pin, strlen(pin)); 1246 free(pin); 1247 pin = NULL; 1248 } 1249 if (r == FIDO_OK) { 1250 if (opts.pin == FIDO_OPT_TRUE || opts.uv == FIDO_OPT_TRUE) { 1251 r = fido_assert_set_uv(assert, FIDO_OPT_TRUE); 1252 if (r != FIDO_OK) { 1253 debug_dbg(cfg, "Failed to set UV"); 1254 goto out; 1255 } 1256 } 1257 r = fido_assert_verify(assert, 0, pk.type, pk.ptr); 1258 if (r == FIDO_OK) { 1259 retval = PAM_SUCCESS; 1260 goto out; 1261 } 1262 } 1263 } 1264 } else { 1265 debug_dbg(cfg, "Device for this keyhandle is not present"); 1266 } 1267 1268 i++; 1269 1270 fido_dev_info_free(&devlist, ndevs); 1271 1272 devlist = fido_dev_info_new(DEVLIST_LEN); 1273 if (!devlist) { 1274 debug_dbg(cfg, "Unable to allocate devlist"); 1275 goto out; 1276 } 1277 1278 r = fido_dev_info_manifest(devlist, DEVLIST_LEN, &ndevs); 1279 if (r != FIDO_OK) { 1280 debug_dbg(cfg, "Unable to discover device(s), %s (%d)", fido_strerr(r), 1281 r); 1282 goto out; 1283 } 1284 1285 if (ndevs > ndevs_prev) { 1286 debug_dbg(cfg, 1287 "Devices max_index has changed: %zu (was %zu). Starting over", 1288 ndevs, ndevs_prev); 1289 ndevs_prev = ndevs; 1290 i = 0; 1291 } 1292 1293 for (size_t j = 0; authlist[j] != NULL; j++) { 1294 fido_dev_close(authlist[j]); 1295 fido_dev_free(&authlist[j]); 1296 } 1297 1298 fido_assert_free(&assert); 1299 } 1300 1301 out: 1302 reset_pk(&pk); 1303 fido_assert_free(&assert); 1304 fido_dev_info_free(&devlist, ndevs); 1305 1306 if (authlist) { 1307 for (size_t j = 0; authlist[j] != NULL; j++) { 1308 fido_dev_close(authlist[j]); 1309 fido_dev_free(&authlist[j]); 1310 } 1311 free(authlist); 1312 } 1313 1314 return retval; 1315 } 1316 1317 #define MAX_PROMPT_LEN (1024) 1318 1319 static int manual_get_assert(const cfg_t *cfg, const char *prompt, 1320 pam_handle_t *pamh, fido_assert_t *assert) { 1321 char *b64_cdh = NULL; 1322 char *b64_rpid = NULL; 1323 char *b64_authdata = NULL; 1324 char *b64_sig = NULL; 1325 unsigned char *authdata = NULL; 1326 unsigned char *sig = NULL; 1327 size_t authdata_len; 1328 size_t sig_len; 1329 int r; 1330 int ok = 0; 1331 1332 b64_cdh = converse(pamh, PAM_PROMPT_ECHO_ON, prompt); 1333 b64_rpid = converse(pamh, PAM_PROMPT_ECHO_ON, prompt); 1334 b64_authdata = converse(pamh, PAM_PROMPT_ECHO_ON, prompt); 1335 b64_sig = converse(pamh, PAM_PROMPT_ECHO_ON, prompt); 1336 1337 if (!b64_decode(b64_authdata, (void **) &authdata, &authdata_len)) { 1338 debug_dbg(cfg, "Failed to decode authenticator data"); 1339 goto err; 1340 } 1341 1342 if (!b64_decode(b64_sig, (void **) &sig, &sig_len)) { 1343 debug_dbg(cfg, "Failed to decode signature"); 1344 goto err; 1345 } 1346 1347 r = fido_assert_set_count(assert, 1); 1348 if (r != FIDO_OK) { 1349 debug_dbg(cfg, "Failed to set signature count of assertion"); 1350 goto err; 1351 } 1352 1353 r = fido_assert_set_authdata(assert, 0, authdata, authdata_len); 1354 if (r != FIDO_OK) { 1355 debug_dbg(cfg, "Failed to set authdata of assertion"); 1356 goto err; 1357 } 1358 1359 r = fido_assert_set_sig(assert, 0, sig, sig_len); 1360 if (r != FIDO_OK) { 1361 debug_dbg(cfg, "Failed to set signature of assertion"); 1362 goto err; 1363 } 1364 1365 ok = 1; 1366 err: 1367 free(b64_cdh); 1368 free(b64_rpid); 1369 free(b64_authdata); 1370 free(b64_sig); 1371 free(authdata); 1372 free(sig); 1373 1374 return ok; 1375 } 1376 1377 int do_manual_authentication(const cfg_t *cfg, const device_t *devices, 1378 const unsigned n_devs, pam_handle_t *pamh) { 1379 fido_assert_t **assert = NULL; 1380 struct pk *pk = NULL; 1381 char *b64_challenge = NULL; 1382 char prompt[MAX_PROMPT_LEN]; 1383 char buf[MAX_PROMPT_LEN]; 1384 int retval = PAM_AUTH_ERR; 1385 int n; 1386 int r; 1387 unsigned i = 0; 1388 struct opts opts; 1389 1390 init_opts(&opts); 1391 assert = calloc(n_devs, sizeof(*assert)); 1392 if (assert == NULL) 1393 goto out; 1394 pk = calloc(n_devs, sizeof(*pk)); 1395 if (pk == NULL) 1396 goto out; 1397 1398 #ifndef WITH_FUZZING 1399 fido_init(cfg->debug ? FIDO_DEBUG : 0); 1400 #else 1401 fido_init(0); 1402 #endif 1403 1404 for (i = 0; i < n_devs; ++i) { 1405 /* options used during authentication */ 1406 parse_opts(cfg, devices[i].attributes, &opts); 1407 assert[i] = prepare_assert(cfg, &devices[i], &opts); 1408 if (assert[i] == NULL) { 1409 debug_dbg(cfg, "Failed to prepare assert"); 1410 goto out; 1411 } 1412 1413 debug_dbg(cfg, "Attempting authentication with device number %d", i + 1); 1414 1415 if (!parse_pk(cfg, devices[i].old_format, devices[i].coseType, 1416 devices[i].publicKey, &pk[i])) { 1417 debug_dbg(cfg, "Unable to parse public key %u", i); 1418 goto out; 1419 } 1420 1421 if (!b64_encode(fido_assert_clientdata_hash_ptr(assert[i]), 1422 fido_assert_clientdata_hash_len(assert[i]), 1423 &b64_challenge)) { 1424 debug_dbg(cfg, "Failed to encode challenge"); 1425 goto out; 1426 } 1427 1428 debug_dbg(cfg, "Challenge: %s", b64_challenge); 1429 1430 n = snprintf(prompt, sizeof(prompt), "Challenge #%d:", i + 1); 1431 if (n <= 0 || (size_t) n >= sizeof(prompt)) { 1432 debug_dbg(cfg, "Failed to print challenge prompt"); 1433 goto out; 1434 } 1435 1436 converse(pamh, PAM_TEXT_INFO, prompt); 1437 1438 n = snprintf(buf, sizeof(buf), "%s\n%s\n%s", b64_challenge, cfg->origin, 1439 devices[i].keyHandle); 1440 if (n <= 0 || (size_t) n >= sizeof(buf)) { 1441 debug_dbg(cfg, "Failed to print fido2-assert input string"); 1442 goto out; 1443 } 1444 1445 converse(pamh, PAM_TEXT_INFO, buf); 1446 1447 free(b64_challenge); 1448 b64_challenge = NULL; 1449 } 1450 1451 converse(pamh, PAM_TEXT_INFO, 1452 "Please pass the challenge(s) above to fido2-assert, and " 1453 "paste the results in the prompt below."); 1454 1455 for (i = 0; i < n_devs; ++i) { 1456 n = snprintf(prompt, sizeof(prompt), "Response #%d: ", i + 1); 1457 if (n <= 0 || (size_t) n >= sizeof(prompt)) { 1458 debug_dbg(cfg, "Failed to print response prompt"); 1459 goto out; 1460 } 1461 1462 if (!manual_get_assert(cfg, prompt, pamh, assert[i])) { 1463 debug_dbg(cfg, "Failed to get assert %u", i); 1464 goto out; 1465 } 1466 1467 r = fido_assert_verify(assert[i], 0, pk[i].type, pk[i].ptr); 1468 if (r == FIDO_OK) { 1469 retval = PAM_SUCCESS; 1470 break; 1471 } 1472 } 1473 1474 out: 1475 for (i = 0; i < n_devs; i++) { 1476 fido_assert_free(&assert[i]); 1477 reset_pk(&pk[i]); 1478 } 1479 free(assert); 1480 free(pk); 1481 free(b64_challenge); 1482 1483 return retval; 1484 } 1485 1486 static int _converse(pam_handle_t *pamh, int nargs, 1487 const struct pam_message **message, 1488 struct pam_response **response) { 1489 struct pam_conv *conv; 1490 int retval; 1491 1492 retval = pam_get_item(pamh, PAM_CONV, (void *) &conv); 1493 1494 if (retval != PAM_SUCCESS) { 1495 return retval; 1496 } 1497 1498 return conv->conv(nargs, message, response, conv->appdata_ptr); 1499 } 1500 1501 char *converse(pam_handle_t *pamh, int echocode, const char *prompt) { 1502 const struct pam_message msg = {.msg_style = echocode, 1503 .msg = (char *) (uintptr_t) prompt}; 1504 const struct pam_message *msgs = &msg; 1505 struct pam_response *resp = NULL; 1506 int retval = _converse(pamh, 1, &msgs, &resp); 1507 char *ret = NULL; 1508 1509 if (retval != PAM_SUCCESS || resp == NULL || resp->resp == NULL || 1510 *resp->resp == '\000') { 1511 1512 if (retval == PAM_SUCCESS && resp && resp->resp) { 1513 ret = resp->resp; 1514 } 1515 } else { 1516 ret = resp->resp; 1517 } 1518 1519 // Deallocate temporary storage. 1520 if (resp) { 1521 if (!ret) { 1522 free(resp->resp); 1523 } 1524 free(resp); 1525 } 1526 1527 return ret; 1528 } 1529 1530 #ifndef RANDOM_DEV 1531 #define RANDOM_DEV "/dev/urandom" 1532 #endif 1533 1534 int random_bytes(void *buf, size_t cnt) { 1535 int fd; 1536 ssize_t n; 1537 1538 fd = open(RANDOM_DEV, O_RDONLY); 1539 if (fd < 0) 1540 return (0); 1541 1542 n = read(fd, buf, cnt); 1543 close(fd); 1544 if (n < 0 || (size_t) n != cnt) 1545 return (0); 1546 1547 return (1); 1548 } 1549