1 /* $NetBSD: sk-usbhid.c,v 1.8 2022/10/05 22:39:36 christos Exp $ */ 2 /* $OpenBSD: sk-usbhid.c,v 1.45 2022/09/14 00:14:37 djm Exp $ */ 3 4 /* 5 * Copyright (c) 2019 Markus Friedl 6 * Copyright (c) 2020 Pedro Martelletto 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 #include "includes.h" 21 __RCSID("$NetBSD: sk-usbhid.c,v 1.8 2022/10/05 22:39:36 christos Exp $"); 22 23 #include <stdint.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <stdio.h> 27 #include <stddef.h> 28 #include <stdarg.h> 29 #include <time.h> 30 31 #ifdef WITH_OPENSSL 32 #include <openssl/opensslv.h> 33 #include <openssl/crypto.h> 34 #include <openssl/bn.h> 35 #include <openssl/ec.h> 36 #include <openssl/ecdsa.h> 37 #include <openssl/evp.h> 38 #endif /* WITH_OPENSSL */ 39 40 #include <fido.h> 41 #include <fido/credman.h> 42 43 #ifndef SK_STANDALONE 44 # include "log.h" 45 # include "xmalloc.h" 46 # include "misc.h" 47 /* 48 * If building as part of OpenSSH, then rename exported functions. 49 * This must be done before including sk-api.h. 50 */ 51 # define sk_api_version ssh_sk_api_version 52 # define sk_enroll ssh_sk_enroll 53 # define sk_sign ssh_sk_sign 54 # define sk_load_resident_keys ssh_sk_load_resident_keys 55 #endif /* !SK_STANDALONE */ 56 57 #include "sk-api.h" 58 59 /* #define SK_DEBUG 1 */ 60 61 #ifdef SK_DEBUG 62 #define SSH_FIDO_INIT_ARG FIDO_DEBUG 63 #else 64 #define SSH_FIDO_INIT_ARG 0 65 #endif 66 67 #define MAX_FIDO_DEVICES 8 68 #define FIDO_POLL_MS 50 69 #define SELECT_MS 15000 70 #define POLL_SLEEP_NS 200000000 71 72 /* Compatibility with OpenSSH 1.0.x */ 73 #if (OPENSSL_VERSION_NUMBER < 0x10100000L) 74 #define ECDSA_SIG_get0(sig, pr, ps) \ 75 do { \ 76 (*pr) = sig->r; \ 77 (*ps) = sig->s; \ 78 } while (0) 79 #endif 80 #ifndef FIDO_ERR_OPERATION_DENIED 81 #define FIDO_ERR_OPERATION_DENIED 0x27 82 #endif 83 84 struct sk_usbhid { 85 fido_dev_t *dev; 86 char *path; 87 }; 88 89 /* Return the version of the middleware API */ 90 uint32_t sk_api_version(void); 91 92 /* Enroll a U2F key (private key generation) */ 93 int sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, 94 const char *application, uint8_t flags, const char *pin, 95 struct sk_option **options, struct sk_enroll_response **enroll_response); 96 97 /* Sign a challenge */ 98 int sk_sign(uint32_t alg, const uint8_t *data, size_t data_len, 99 const char *application, const uint8_t *key_handle, size_t key_handle_len, 100 uint8_t flags, const char *pin, struct sk_option **options, 101 struct sk_sign_response **sign_response); 102 103 /* Load resident keys */ 104 int sk_load_resident_keys(const char *pin, struct sk_option **options, 105 struct sk_resident_key ***rks, size_t *nrks); 106 107 static void skdebug(const char *func, const char *fmt, ...) 108 __attribute__((__format__ (printf, 2, 3))); 109 110 static void 111 skdebug(const char *func, const char *fmt, ...) 112 { 113 #if !defined(SK_STANDALONE) 114 char *msg; 115 va_list ap; 116 117 va_start(ap, fmt); 118 xvasprintf(&msg, fmt, ap); 119 va_end(ap); 120 debug("%s: %s", func, msg); 121 free(msg); 122 #elif defined(SK_DEBUG) 123 va_list ap; 124 125 va_start(ap, fmt); 126 fprintf(stderr, "%s: ", func); 127 vfprintf(stderr, fmt, ap); 128 fputc('\n', stderr); 129 va_end(ap); 130 #else 131 (void)func; /* XXX */ 132 (void)fmt; /* XXX */ 133 #endif 134 } 135 136 uint32_t 137 sk_api_version(void) 138 { 139 return SSH_SK_VERSION_MAJOR; 140 } 141 142 static struct sk_usbhid * 143 sk_open(const char *path) 144 { 145 struct sk_usbhid *sk; 146 int r; 147 148 if (path == NULL) { 149 skdebug(__func__, "path == NULL"); 150 return NULL; 151 } 152 if ((sk = calloc(1, sizeof(*sk))) == NULL) { 153 skdebug(__func__, "calloc sk failed"); 154 return NULL; 155 } 156 if ((sk->path = strdup(path)) == NULL) { 157 skdebug(__func__, "strdup path failed"); 158 free(sk); 159 return NULL; 160 } 161 if ((sk->dev = fido_dev_new()) == NULL) { 162 skdebug(__func__, "fido_dev_new failed"); 163 free(sk->path); 164 free(sk); 165 return NULL; 166 } 167 if ((r = fido_dev_open(sk->dev, sk->path)) != FIDO_OK) { 168 skdebug(__func__, "fido_dev_open %s failed: %s", sk->path, 169 fido_strerr(r)); 170 fido_dev_free(&sk->dev); 171 free(sk->path); 172 free(sk); 173 return NULL; 174 } 175 return sk; 176 } 177 178 static void 179 sk_close(struct sk_usbhid *sk) 180 { 181 if (sk == NULL) 182 return; 183 fido_dev_cancel(sk->dev); /* cancel any pending operation */ 184 fido_dev_close(sk->dev); 185 fido_dev_free(&sk->dev); 186 free(sk->path); 187 free(sk); 188 } 189 190 static struct sk_usbhid ** 191 sk_openv(const fido_dev_info_t *devlist, size_t ndevs, size_t *nopen) 192 { 193 const fido_dev_info_t *di; 194 struct sk_usbhid **skv; 195 size_t i; 196 197 *nopen = 0; 198 if ((skv = calloc(ndevs, sizeof(*skv))) == NULL) { 199 skdebug(__func__, "calloc skv failed"); 200 return NULL; 201 } 202 for (i = 0; i < ndevs; i++) { 203 if ((di = fido_dev_info_ptr(devlist, i)) == NULL) 204 skdebug(__func__, "fido_dev_info_ptr failed"); 205 else if ((skv[*nopen] = sk_open(fido_dev_info_path(di))) == NULL) 206 skdebug(__func__, "sk_open failed"); 207 else 208 (*nopen)++; 209 } 210 if (*nopen == 0) { 211 for (i = 0; i < ndevs; i++) 212 sk_close(skv[i]); 213 free(skv); 214 skv = NULL; 215 } 216 217 return skv; 218 } 219 220 static void 221 sk_closev(struct sk_usbhid **skv, size_t nsk) 222 { 223 size_t i; 224 225 for (i = 0; i < nsk; i++) 226 sk_close(skv[i]); 227 free(skv); 228 } 229 230 static int 231 sk_touch_begin(struct sk_usbhid **skv, size_t nsk) 232 { 233 size_t i, ok = 0; 234 int r; 235 236 for (i = 0; i < nsk; i++) 237 if ((r = fido_dev_get_touch_begin(skv[i]->dev)) != FIDO_OK) 238 skdebug(__func__, "fido_dev_get_touch_begin %s failed:" 239 " %s", skv[i]->path, fido_strerr(r)); 240 else 241 ok++; 242 243 return ok ? 0 : -1; 244 } 245 246 static int 247 sk_touch_poll(struct sk_usbhid **skv, size_t nsk, int *touch, size_t *idx) 248 { 249 struct timespec ts_pause; 250 size_t npoll, i; 251 int r; 252 253 ts_pause.tv_sec = 0; 254 ts_pause.tv_nsec = POLL_SLEEP_NS; 255 nanosleep(&ts_pause, NULL); 256 npoll = nsk; 257 for (i = 0; i < nsk; i++) { 258 if (skv[i] == NULL) 259 continue; /* device discarded */ 260 skdebug(__func__, "polling %s", skv[i]->path); 261 if ((r = fido_dev_get_touch_status(skv[i]->dev, touch, 262 FIDO_POLL_MS)) != FIDO_OK) { 263 skdebug(__func__, "fido_dev_get_touch_status %s: %s", 264 skv[i]->path, fido_strerr(r)); 265 sk_close(skv[i]); /* discard device */ 266 skv[i] = NULL; 267 if (--npoll == 0) { 268 skdebug(__func__, "no device left to poll"); 269 return -1; 270 } 271 } else if (*touch) { 272 *idx = i; 273 return 0; 274 } 275 } 276 *touch = 0; 277 return 0; 278 } 279 280 /* Check if the specified key handle exists on a given sk. */ 281 static int 282 sk_try(const struct sk_usbhid *sk, const char *application, 283 const uint8_t *key_handle, size_t key_handle_len) 284 { 285 fido_assert_t *assert = NULL; 286 int r = FIDO_ERR_INTERNAL; 287 uint8_t message[32]; 288 289 memset(message, '\0', sizeof(message)); 290 if ((assert = fido_assert_new()) == NULL) { 291 skdebug(__func__, "fido_assert_new failed"); 292 goto out; 293 } 294 /* generate an invalid signature on FIDO2 tokens */ 295 if ((r = fido_assert_set_clientdata(assert, message, 296 sizeof(message))) != FIDO_OK) { 297 skdebug(__func__, "fido_assert_set_clientdata: %s", 298 fido_strerr(r)); 299 goto out; 300 } 301 if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK) { 302 skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r)); 303 goto out; 304 } 305 if ((r = fido_assert_allow_cred(assert, key_handle, 306 key_handle_len)) != FIDO_OK) { 307 skdebug(__func__, "fido_assert_allow_cred: %s", fido_strerr(r)); 308 goto out; 309 } 310 if ((r = fido_assert_set_up(assert, FIDO_OPT_FALSE)) != FIDO_OK) { 311 skdebug(__func__, "fido_assert_up: %s", fido_strerr(r)); 312 goto out; 313 } 314 r = fido_dev_get_assert(sk->dev, assert, NULL); 315 skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r)); 316 if (r == FIDO_ERR_USER_PRESENCE_REQUIRED) { 317 /* U2F tokens may return this */ 318 r = FIDO_OK; 319 } 320 out: 321 fido_assert_free(&assert); 322 323 return r != FIDO_OK ? -1 : 0; 324 } 325 326 static int 327 check_sk_options(fido_dev_t *dev, const char *opt, int *ret) 328 { 329 fido_cbor_info_t *info; 330 char * const *name; 331 const bool *value; 332 size_t len, i; 333 int r; 334 335 *ret = -1; 336 337 if (!fido_dev_is_fido2(dev)) { 338 skdebug(__func__, "device is not fido2"); 339 return 0; 340 } 341 if ((info = fido_cbor_info_new()) == NULL) { 342 skdebug(__func__, "fido_cbor_info_new failed"); 343 return -1; 344 } 345 if ((r = fido_dev_get_cbor_info(dev, info)) != FIDO_OK) { 346 skdebug(__func__, "fido_dev_get_cbor_info: %s", fido_strerr(r)); 347 fido_cbor_info_free(&info); 348 return -1; 349 } 350 name = fido_cbor_info_options_name_ptr(info); 351 value = fido_cbor_info_options_value_ptr(info); 352 len = fido_cbor_info_options_len(info); 353 for (i = 0; i < len; i++) { 354 if (!strcmp(name[i], opt)) { 355 *ret = value[i]; 356 break; 357 } 358 } 359 fido_cbor_info_free(&info); 360 if (*ret == -1) 361 skdebug(__func__, "option %s is unknown", opt); 362 else 363 skdebug(__func__, "option %s is %s", opt, *ret ? "on" : "off"); 364 365 return 0; 366 } 367 368 static struct sk_usbhid * 369 sk_select_by_cred(const fido_dev_info_t *devlist, size_t ndevs, 370 const char *application, const uint8_t *key_handle, size_t key_handle_len) 371 { 372 struct sk_usbhid **skv, *sk; 373 size_t skvcnt, i; 374 int internal_uv; 375 376 if ((skv = sk_openv(devlist, ndevs, &skvcnt)) == NULL) { 377 skdebug(__func__, "sk_openv failed"); 378 return NULL; 379 } 380 if (skvcnt == 1 && check_sk_options(skv[0]->dev, "uv", 381 &internal_uv) == 0 && internal_uv != -1) { 382 sk = skv[0]; 383 skv[0] = NULL; 384 goto out; 385 } 386 sk = NULL; 387 for (i = 0; i < skvcnt; i++) { 388 if (sk_try(skv[i], application, key_handle, 389 key_handle_len) == 0) { 390 sk = skv[i]; 391 skv[i] = NULL; 392 skdebug(__func__, "found key in %s", sk->path); 393 break; 394 } 395 } 396 out: 397 sk_closev(skv, skvcnt); 398 return sk; 399 } 400 401 static struct sk_usbhid * 402 sk_select_by_touch(const fido_dev_info_t *devlist, size_t ndevs) 403 { 404 struct sk_usbhid **skv, *sk; 405 struct timeval tv_start, tv_now, tv_delta; 406 size_t skvcnt, idx; 407 int touch, ms_remain; 408 409 if ((skv = sk_openv(devlist, ndevs, &skvcnt)) == NULL) { 410 skdebug(__func__, "sk_openv failed"); 411 return NULL; 412 } 413 sk = NULL; 414 if (skvcnt < 2) { 415 if (skvcnt == 1) { 416 /* single candidate */ 417 sk = skv[0]; 418 skv[0] = NULL; 419 } 420 goto out; 421 } 422 if (sk_touch_begin(skv, skvcnt) == -1) { 423 skdebug(__func__, "sk_touch_begin failed"); 424 goto out; 425 } 426 monotime_tv(&tv_start); 427 do { 428 if (sk_touch_poll(skv, skvcnt, &touch, &idx) == -1) { 429 skdebug(__func__, "sk_touch_poll failed"); 430 goto out; 431 } 432 if (touch) { 433 sk = skv[idx]; 434 skv[idx] = NULL; 435 goto out; 436 } 437 monotime_tv(&tv_now); 438 timersub(&tv_now, &tv_start, &tv_delta); 439 ms_remain = SELECT_MS - tv_delta.tv_sec * 1000 - 440 tv_delta.tv_usec / 1000; 441 } while (ms_remain >= FIDO_POLL_MS); 442 skdebug(__func__, "timeout"); 443 out: 444 sk_closev(skv, skvcnt); 445 return sk; 446 } 447 448 static struct sk_usbhid * 449 sk_probe(const char *application, const uint8_t *key_handle, 450 size_t key_handle_len, int probe_resident) 451 { 452 struct sk_usbhid *sk; 453 fido_dev_info_t *devlist; 454 size_t ndevs; 455 int r; 456 457 if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) { 458 skdebug(__func__, "fido_dev_info_new failed"); 459 return NULL; 460 } 461 if ((r = fido_dev_info_manifest(devlist, MAX_FIDO_DEVICES, 462 &ndevs)) != FIDO_OK) { 463 skdebug(__func__, "fido_dev_info_manifest failed: %s", 464 fido_strerr(r)); 465 fido_dev_info_free(&devlist, MAX_FIDO_DEVICES); 466 return NULL; 467 } 468 skdebug(__func__, "%zu device(s) detected", ndevs); 469 if (ndevs == 0) { 470 sk = NULL; 471 } else if (application != NULL && key_handle != NULL) { 472 skdebug(__func__, "selecting sk by cred"); 473 sk = sk_select_by_cred(devlist, ndevs, application, key_handle, 474 key_handle_len); 475 } else { 476 skdebug(__func__, "selecting sk by touch"); 477 sk = sk_select_by_touch(devlist, ndevs); 478 } 479 fido_dev_info_free(&devlist, MAX_FIDO_DEVICES); 480 return sk; 481 } 482 483 #ifdef WITH_OPENSSL 484 /* 485 * The key returned via fido_cred_pubkey_ptr() is in affine coordinates, 486 * but the API expects a SEC1 octet string. 487 */ 488 static int 489 pack_public_key_ecdsa(const fido_cred_t *cred, 490 struct sk_enroll_response *response) 491 { 492 const uint8_t *ptr; 493 BIGNUM *x = NULL, *y = NULL; 494 EC_POINT *q = NULL; 495 EC_GROUP *g = NULL; 496 int ret = -1; 497 498 response->public_key = NULL; 499 response->public_key_len = 0; 500 501 if ((x = BN_new()) == NULL || 502 (y = BN_new()) == NULL || 503 (g = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)) == NULL || 504 (q = EC_POINT_new(g)) == NULL) { 505 skdebug(__func__, "libcrypto setup failed"); 506 goto out; 507 } 508 if ((ptr = fido_cred_pubkey_ptr(cred)) == NULL) { 509 skdebug(__func__, "fido_cred_pubkey_ptr failed"); 510 goto out; 511 } 512 if (fido_cred_pubkey_len(cred) != 64) { 513 skdebug(__func__, "bad fido_cred_pubkey_len %zu", 514 fido_cred_pubkey_len(cred)); 515 goto out; 516 } 517 518 if (BN_bin2bn(ptr, 32, x) == NULL || 519 BN_bin2bn(ptr + 32, 32, y) == NULL) { 520 skdebug(__func__, "BN_bin2bn failed"); 521 goto out; 522 } 523 if (EC_POINT_set_affine_coordinates_GFp(g, q, x, y, NULL) != 1) { 524 skdebug(__func__, "EC_POINT_set_affine_coordinates_GFp failed"); 525 goto out; 526 } 527 response->public_key_len = EC_POINT_point2oct(g, q, 528 POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); 529 if (response->public_key_len == 0 || response->public_key_len > 2048) { 530 skdebug(__func__, "bad pubkey length %zu", 531 response->public_key_len); 532 goto out; 533 } 534 if ((response->public_key = malloc(response->public_key_len)) == NULL) { 535 skdebug(__func__, "malloc pubkey failed"); 536 goto out; 537 } 538 if (EC_POINT_point2oct(g, q, POINT_CONVERSION_UNCOMPRESSED, 539 response->public_key, response->public_key_len, NULL) == 0) { 540 skdebug(__func__, "EC_POINT_point2oct failed"); 541 goto out; 542 } 543 /* success */ 544 ret = 0; 545 out: 546 if (ret != 0 && response->public_key != NULL) { 547 memset(response->public_key, 0, response->public_key_len); 548 free(response->public_key); 549 response->public_key = NULL; 550 } 551 EC_POINT_free(q); 552 EC_GROUP_free(g); 553 BN_clear_free(x); 554 BN_clear_free(y); 555 return ret; 556 } 557 #endif /* WITH_OPENSSL */ 558 559 static int 560 pack_public_key_ed25519(const fido_cred_t *cred, 561 struct sk_enroll_response *response) 562 { 563 const uint8_t *ptr; 564 size_t len; 565 int ret = -1; 566 567 response->public_key = NULL; 568 response->public_key_len = 0; 569 570 if ((len = fido_cred_pubkey_len(cred)) != 32) { 571 skdebug(__func__, "bad fido_cred_pubkey_len len %zu", len); 572 goto out; 573 } 574 if ((ptr = fido_cred_pubkey_ptr(cred)) == NULL) { 575 skdebug(__func__, "fido_cred_pubkey_ptr failed"); 576 goto out; 577 } 578 response->public_key_len = len; 579 if ((response->public_key = malloc(response->public_key_len)) == NULL) { 580 skdebug(__func__, "malloc pubkey failed"); 581 goto out; 582 } 583 memcpy(response->public_key, ptr, len); 584 ret = 0; 585 out: 586 if (ret != 0) 587 free(response->public_key); 588 return ret; 589 } 590 591 static int 592 pack_public_key(uint32_t alg, const fido_cred_t *cred, 593 struct sk_enroll_response *response) 594 { 595 switch(alg) { 596 #ifdef WITH_OPENSSL 597 case SSH_SK_ECDSA: 598 return pack_public_key_ecdsa(cred, response); 599 #endif /* WITH_OPENSSL */ 600 case SSH_SK_ED25519: 601 return pack_public_key_ed25519(cred, response); 602 default: 603 return -1; 604 } 605 } 606 607 static int 608 fidoerr_to_skerr(int fidoerr) 609 { 610 switch (fidoerr) { 611 case FIDO_ERR_UNSUPPORTED_OPTION: 612 case FIDO_ERR_UNSUPPORTED_ALGORITHM: 613 return SSH_SK_ERR_UNSUPPORTED; 614 case FIDO_ERR_PIN_REQUIRED: 615 case FIDO_ERR_PIN_INVALID: 616 case FIDO_ERR_OPERATION_DENIED: 617 return SSH_SK_ERR_PIN_REQUIRED; 618 default: 619 return -1; 620 } 621 } 622 623 static int 624 check_enroll_options(struct sk_option **options, char **devicep, 625 uint8_t *user_id, size_t user_id_len) 626 { 627 size_t i; 628 629 if (options == NULL) 630 return 0; 631 for (i = 0; options[i] != NULL; i++) { 632 if (strcmp(options[i]->name, "device") == 0) { 633 if ((*devicep = strdup(options[i]->value)) == NULL) { 634 skdebug(__func__, "strdup device failed"); 635 return -1; 636 } 637 skdebug(__func__, "requested device %s", *devicep); 638 } else if (strcmp(options[i]->name, "user") == 0) { 639 if (strlcpy((char *)user_id, options[i]->value, user_id_len) >= 640 user_id_len) { 641 skdebug(__func__, "user too long"); 642 return -1; 643 } 644 skdebug(__func__, "requested user %s", 645 (char *)user_id); 646 } else { 647 skdebug(__func__, "requested unsupported option %s", 648 options[i]->name); 649 if (options[i]->required) { 650 skdebug(__func__, "unknown required option"); 651 return -1; 652 } 653 } 654 } 655 return 0; 656 } 657 658 static int 659 key_lookup(fido_dev_t *dev, const char *application, const uint8_t *user_id, 660 size_t user_id_len, const char *pin) 661 { 662 fido_assert_t *assert = NULL; 663 uint8_t message[32]; 664 int r = FIDO_ERR_INTERNAL; 665 int sk_supports_uv, uv; 666 size_t i; 667 668 memset(message, '\0', sizeof(message)); 669 if ((assert = fido_assert_new()) == NULL) { 670 skdebug(__func__, "fido_assert_new failed"); 671 goto out; 672 } 673 /* generate an invalid signature on FIDO2 tokens */ 674 if ((r = fido_assert_set_clientdata(assert, message, 675 sizeof(message))) != FIDO_OK) { 676 skdebug(__func__, "fido_assert_set_clientdata: %s", 677 fido_strerr(r)); 678 goto out; 679 } 680 if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK) { 681 skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r)); 682 goto out; 683 } 684 if ((r = fido_assert_set_up(assert, FIDO_OPT_FALSE)) != FIDO_OK) { 685 skdebug(__func__, "fido_assert_set_up: %s", fido_strerr(r)); 686 goto out; 687 } 688 uv = FIDO_OPT_OMIT; 689 if (pin == NULL && check_sk_options(dev, "uv", &sk_supports_uv) == 0 && 690 sk_supports_uv != -1) 691 uv = FIDO_OPT_TRUE; 692 if ((r = fido_assert_set_uv(assert, uv)) != FIDO_OK) { 693 skdebug(__func__, "fido_assert_set_uv: %s", fido_strerr(r)); 694 goto out; 695 } 696 if ((r = fido_dev_get_assert(dev, assert, pin)) != FIDO_OK) { 697 skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r)); 698 goto out; 699 } 700 r = FIDO_ERR_NO_CREDENTIALS; 701 skdebug(__func__, "%zu signatures returned", fido_assert_count(assert)); 702 for (i = 0; i < fido_assert_count(assert); i++) { 703 if (fido_assert_user_id_len(assert, i) == user_id_len && 704 memcmp(fido_assert_user_id_ptr(assert, i), user_id, 705 user_id_len) == 0) { 706 skdebug(__func__, "credential exists"); 707 r = FIDO_OK; 708 goto out; 709 } 710 } 711 out: 712 fido_assert_free(&assert); 713 714 return r; 715 } 716 717 int 718 sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, 719 const char *application, uint8_t flags, const char *pin, 720 struct sk_option **options, struct sk_enroll_response **enroll_response) 721 { 722 fido_cred_t *cred = NULL; 723 const uint8_t *ptr; 724 uint8_t user_id[32]; 725 struct sk_usbhid *sk = NULL; 726 struct sk_enroll_response *response = NULL; 727 size_t len; 728 int credprot; 729 int cose_alg; 730 int ret = SSH_SK_ERR_GENERAL; 731 int r; 732 char *device = NULL; 733 734 fido_init(SSH_FIDO_INIT_ARG); 735 736 if (enroll_response == NULL) { 737 skdebug(__func__, "enroll_response == NULL"); 738 goto out; 739 } 740 *enroll_response = NULL; 741 memset(user_id, 0, sizeof(user_id)); 742 if (check_enroll_options(options, &device, user_id, 743 sizeof(user_id)) != 0) 744 goto out; /* error already logged */ 745 746 switch(alg) { 747 #ifdef WITH_OPENSSL 748 case SSH_SK_ECDSA: 749 cose_alg = COSE_ES256; 750 break; 751 #endif /* WITH_OPENSSL */ 752 case SSH_SK_ED25519: 753 cose_alg = COSE_EDDSA; 754 break; 755 default: 756 skdebug(__func__, "unsupported key type %d", alg); 757 goto out; 758 } 759 if (device != NULL) 760 sk = sk_open(device); 761 else 762 sk = sk_probe(NULL, NULL, 0, 0); 763 if (sk == NULL) { 764 ret = SSH_SK_ERR_DEVICE_NOT_FOUND; 765 skdebug(__func__, "failed to find sk"); 766 goto out; 767 } 768 skdebug(__func__, "using device %s", sk->path); 769 if ((flags & SSH_SK_RESIDENT_KEY) != 0 && 770 (flags & SSH_SK_FORCE_OPERATION) == 0 && 771 (r = key_lookup(sk->dev, application, user_id, sizeof(user_id), 772 pin)) != FIDO_ERR_NO_CREDENTIALS) { 773 if (r != FIDO_OK) { 774 ret = fidoerr_to_skerr(r); 775 skdebug(__func__, "key_lookup failed"); 776 } else { 777 ret = SSH_SK_ERR_CREDENTIAL_EXISTS; 778 skdebug(__func__, "key exists"); 779 } 780 goto out; 781 } 782 if ((cred = fido_cred_new()) == NULL) { 783 skdebug(__func__, "fido_cred_new failed"); 784 goto out; 785 } 786 if ((r = fido_cred_set_type(cred, cose_alg)) != FIDO_OK) { 787 skdebug(__func__, "fido_cred_set_type: %s", fido_strerr(r)); 788 goto out; 789 } 790 if ((r = fido_cred_set_clientdata(cred, 791 challenge, challenge_len)) != FIDO_OK) { 792 skdebug(__func__, "fido_cred_set_clientdata: %s", 793 fido_strerr(r)); 794 goto out; 795 } 796 if ((r = fido_cred_set_rk(cred, (flags & SSH_SK_RESIDENT_KEY) != 0 ? 797 FIDO_OPT_TRUE : FIDO_OPT_OMIT)) != FIDO_OK) { 798 skdebug(__func__, "fido_cred_set_rk: %s", fido_strerr(r)); 799 goto out; 800 } 801 if ((r = fido_cred_set_user(cred, user_id, sizeof(user_id), 802 "openssh", "openssh", NULL)) != FIDO_OK) { 803 skdebug(__func__, "fido_cred_set_user: %s", fido_strerr(r)); 804 goto out; 805 } 806 if ((r = fido_cred_set_rp(cred, application, NULL)) != FIDO_OK) { 807 skdebug(__func__, "fido_cred_set_rp: %s", fido_strerr(r)); 808 goto out; 809 } 810 if ((flags & (SSH_SK_RESIDENT_KEY|SSH_SK_USER_VERIFICATION_REQD)) != 0) { 811 if (!fido_dev_supports_cred_prot(sk->dev)) { 812 skdebug(__func__, "%s does not support credprot, " 813 "refusing to create unprotected " 814 "resident/verify-required key", sk->path); 815 ret = SSH_SK_ERR_UNSUPPORTED; 816 goto out; 817 } 818 if ((flags & SSH_SK_USER_VERIFICATION_REQD)) 819 credprot = FIDO_CRED_PROT_UV_REQUIRED; 820 else 821 credprot = FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID; 822 823 if ((r = fido_cred_set_prot(cred, credprot)) != FIDO_OK) { 824 skdebug(__func__, "fido_cred_set_prot: %s", 825 fido_strerr(r)); 826 ret = fidoerr_to_skerr(r); 827 goto out; 828 } 829 } 830 if ((r = fido_dev_make_cred(sk->dev, cred, pin)) != FIDO_OK) { 831 skdebug(__func__, "fido_dev_make_cred: %s", fido_strerr(r)); 832 ret = fidoerr_to_skerr(r); 833 goto out; 834 } 835 if (fido_cred_x5c_ptr(cred) != NULL) { 836 if ((r = fido_cred_verify(cred)) != FIDO_OK) { 837 skdebug(__func__, "fido_cred_verify: %s", 838 fido_strerr(r)); 839 goto out; 840 } 841 } else { 842 skdebug(__func__, "self-attested credential"); 843 if ((r = fido_cred_verify_self(cred)) != FIDO_OK) { 844 skdebug(__func__, "fido_cred_verify_self: %s", 845 fido_strerr(r)); 846 goto out; 847 } 848 } 849 if ((response = calloc(1, sizeof(*response))) == NULL) { 850 skdebug(__func__, "calloc response failed"); 851 goto out; 852 } 853 response->flags = flags; 854 if (pack_public_key(alg, cred, response) != 0) { 855 skdebug(__func__, "pack_public_key failed"); 856 goto out; 857 } 858 if ((ptr = fido_cred_id_ptr(cred)) != NULL) { 859 len = fido_cred_id_len(cred); 860 if ((response->key_handle = calloc(1, len)) == NULL) { 861 skdebug(__func__, "calloc key handle failed"); 862 goto out; 863 } 864 memcpy(response->key_handle, ptr, len); 865 response->key_handle_len = len; 866 } 867 if ((ptr = fido_cred_sig_ptr(cred)) != NULL) { 868 len = fido_cred_sig_len(cred); 869 if ((response->signature = calloc(1, len)) == NULL) { 870 skdebug(__func__, "calloc signature failed"); 871 goto out; 872 } 873 memcpy(response->signature, ptr, len); 874 response->signature_len = len; 875 } 876 if ((ptr = fido_cred_x5c_ptr(cred)) != NULL) { 877 len = fido_cred_x5c_len(cred); 878 skdebug(__func__, "attestation cert len=%zu", len); 879 if ((response->attestation_cert = calloc(1, len)) == NULL) { 880 skdebug(__func__, "calloc attestation cert failed"); 881 goto out; 882 } 883 memcpy(response->attestation_cert, ptr, len); 884 response->attestation_cert_len = len; 885 } 886 if ((ptr = fido_cred_authdata_ptr(cred)) != NULL) { 887 len = fido_cred_authdata_len(cred); 888 skdebug(__func__, "authdata len=%zu", len); 889 if ((response->authdata = calloc(1, len)) == NULL) { 890 skdebug(__func__, "calloc authdata failed"); 891 goto out; 892 } 893 memcpy(response->authdata, ptr, len); 894 response->authdata_len = len; 895 } 896 *enroll_response = response; 897 response = NULL; 898 ret = 0; 899 out: 900 free(device); 901 if (response != NULL) { 902 free(response->public_key); 903 free(response->key_handle); 904 free(response->signature); 905 free(response->attestation_cert); 906 free(response->authdata); 907 free(response); 908 } 909 sk_close(sk); 910 fido_cred_free(&cred); 911 return ret; 912 } 913 914 #ifdef WITH_OPENSSL 915 static int 916 pack_sig_ecdsa(fido_assert_t *assert, struct sk_sign_response *response) 917 { 918 ECDSA_SIG *sig = NULL; 919 const BIGNUM *sig_r, *sig_s; 920 const unsigned char *cp; 921 size_t sig_len; 922 int ret = -1; 923 924 cp = fido_assert_sig_ptr(assert, 0); 925 sig_len = fido_assert_sig_len(assert, 0); 926 if ((sig = d2i_ECDSA_SIG(NULL, &cp, sig_len)) == NULL) { 927 skdebug(__func__, "d2i_ECDSA_SIG failed"); 928 goto out; 929 } 930 ECDSA_SIG_get0(sig, &sig_r, &sig_s); 931 response->sig_r_len = BN_num_bytes(sig_r); 932 response->sig_s_len = BN_num_bytes(sig_s); 933 if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL || 934 (response->sig_s = calloc(1, response->sig_s_len)) == NULL) { 935 skdebug(__func__, "calloc signature failed"); 936 goto out; 937 } 938 BN_bn2bin(sig_r, response->sig_r); 939 BN_bn2bin(sig_s, response->sig_s); 940 ret = 0; 941 out: 942 ECDSA_SIG_free(sig); 943 if (ret != 0) { 944 free(response->sig_r); 945 free(response->sig_s); 946 response->sig_r = NULL; 947 response->sig_s = NULL; 948 } 949 return ret; 950 } 951 #endif /* WITH_OPENSSL */ 952 953 static int 954 pack_sig_ed25519(fido_assert_t *assert, struct sk_sign_response *response) 955 { 956 const unsigned char *ptr; 957 size_t len; 958 int ret = -1; 959 960 ptr = fido_assert_sig_ptr(assert, 0); 961 len = fido_assert_sig_len(assert, 0); 962 if (len != 64) { 963 skdebug(__func__, "bad length %zu", len); 964 goto out; 965 } 966 response->sig_r_len = len; 967 if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL) { 968 skdebug(__func__, "calloc signature failed"); 969 goto out; 970 } 971 memcpy(response->sig_r, ptr, len); 972 ret = 0; 973 out: 974 if (ret != 0) { 975 free(response->sig_r); 976 response->sig_r = NULL; 977 } 978 return ret; 979 } 980 981 static int 982 pack_sig(uint32_t alg, fido_assert_t *assert, 983 struct sk_sign_response *response) 984 { 985 switch(alg) { 986 #ifdef WITH_OPENSSL 987 case SSH_SK_ECDSA: 988 return pack_sig_ecdsa(assert, response); 989 #endif /* WITH_OPENSSL */ 990 case SSH_SK_ED25519: 991 return pack_sig_ed25519(assert, response); 992 default: 993 return -1; 994 } 995 } 996 997 /* Checks sk_options for sk_sign() and sk_load_resident_keys() */ 998 static int 999 check_sign_load_resident_options(struct sk_option **options, char **devicep) 1000 { 1001 size_t i; 1002 1003 if (options == NULL) 1004 return 0; 1005 for (i = 0; options[i] != NULL; i++) { 1006 if (strcmp(options[i]->name, "device") == 0) { 1007 if ((*devicep = strdup(options[i]->value)) == NULL) { 1008 skdebug(__func__, "strdup device failed"); 1009 return -1; 1010 } 1011 skdebug(__func__, "requested device %s", *devicep); 1012 } else { 1013 skdebug(__func__, "requested unsupported option %s", 1014 options[i]->name); 1015 if (options[i]->required) { 1016 skdebug(__func__, "unknown required option"); 1017 return -1; 1018 } 1019 } 1020 } 1021 return 0; 1022 } 1023 1024 int 1025 sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, 1026 const char *application, 1027 const uint8_t *key_handle, size_t key_handle_len, 1028 uint8_t flags, const char *pin, struct sk_option **options, 1029 struct sk_sign_response **sign_response) 1030 { 1031 fido_assert_t *assert = NULL; 1032 char *device = NULL; 1033 struct sk_usbhid *sk = NULL; 1034 struct sk_sign_response *response = NULL; 1035 int ret = SSH_SK_ERR_GENERAL, internal_uv; 1036 int r; 1037 1038 fido_init(SSH_FIDO_INIT_ARG); 1039 1040 if (sign_response == NULL) { 1041 skdebug(__func__, "sign_response == NULL"); 1042 goto out; 1043 } 1044 *sign_response = NULL; 1045 if (check_sign_load_resident_options(options, &device) != 0) 1046 goto out; /* error already logged */ 1047 if (device != NULL) 1048 sk = sk_open(device); 1049 else if (pin != NULL || (flags & SSH_SK_USER_VERIFICATION_REQD)) 1050 sk = sk_probe(NULL, NULL, 0, 0); 1051 else 1052 sk = sk_probe(application, key_handle, key_handle_len, 0); 1053 if (sk == NULL) { 1054 ret = SSH_SK_ERR_DEVICE_NOT_FOUND; 1055 skdebug(__func__, "failed to find sk"); 1056 goto out; 1057 } 1058 if ((assert = fido_assert_new()) == NULL) { 1059 skdebug(__func__, "fido_assert_new failed"); 1060 goto out; 1061 } 1062 if ((r = fido_assert_set_clientdata(assert, 1063 data, datalen)) != FIDO_OK) { 1064 skdebug(__func__, "fido_assert_set_clientdata: %s", 1065 fido_strerr(r)); 1066 goto out; 1067 } 1068 if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK) { 1069 skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r)); 1070 goto out; 1071 } 1072 if ((r = fido_assert_allow_cred(assert, key_handle, 1073 key_handle_len)) != FIDO_OK) { 1074 skdebug(__func__, "fido_assert_allow_cred: %s", fido_strerr(r)); 1075 goto out; 1076 } 1077 if ((r = fido_assert_set_up(assert, 1078 (flags & SSH_SK_USER_PRESENCE_REQD) ? 1079 FIDO_OPT_TRUE : FIDO_OPT_FALSE)) != FIDO_OK) { 1080 skdebug(__func__, "fido_assert_set_up: %s", fido_strerr(r)); 1081 goto out; 1082 } 1083 if (pin == NULL && (flags & SSH_SK_USER_VERIFICATION_REQD)) { 1084 if (check_sk_options(sk->dev, "uv", &internal_uv) < 0 || 1085 internal_uv != 1) { 1086 skdebug(__func__, "check_sk_options uv"); 1087 ret = SSH_SK_ERR_PIN_REQUIRED; 1088 goto out; 1089 } 1090 if ((r = fido_assert_set_uv(assert, 1091 FIDO_OPT_TRUE)) != FIDO_OK) { 1092 skdebug(__func__, "fido_assert_set_uv: %s", 1093 fido_strerr(r)); 1094 ret = fidoerr_to_skerr(r); 1095 goto out; 1096 } 1097 } 1098 if ((r = fido_dev_get_assert(sk->dev, assert, pin)) != FIDO_OK) { 1099 skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r)); 1100 ret = fidoerr_to_skerr(r); 1101 goto out; 1102 } 1103 if ((response = calloc(1, sizeof(*response))) == NULL) { 1104 skdebug(__func__, "calloc response failed"); 1105 goto out; 1106 } 1107 response->flags = fido_assert_flags(assert, 0); 1108 response->counter = fido_assert_sigcount(assert, 0); 1109 if (pack_sig(alg, assert, response) != 0) { 1110 skdebug(__func__, "pack_sig failed"); 1111 goto out; 1112 } 1113 *sign_response = response; 1114 response = NULL; 1115 ret = 0; 1116 out: 1117 free(device); 1118 if (response != NULL) { 1119 free(response->sig_r); 1120 free(response->sig_s); 1121 free(response); 1122 } 1123 sk_close(sk); 1124 fido_assert_free(&assert); 1125 return ret; 1126 } 1127 1128 static int 1129 read_rks(struct sk_usbhid *sk, const char *pin, 1130 struct sk_resident_key ***rksp, size_t *nrksp) 1131 { 1132 int ret = SSH_SK_ERR_GENERAL, r = -1, internal_uv; 1133 fido_credman_metadata_t *metadata = NULL; 1134 fido_credman_rp_t *rp = NULL; 1135 fido_credman_rk_t *rk = NULL; 1136 size_t i, j, nrp, nrk, user_id_len; 1137 const fido_cred_t *cred; 1138 const char *rp_id, *rp_name, *user_name; 1139 struct sk_resident_key *srk = NULL, **tmp; 1140 const u_char *user_id; 1141 1142 if (pin == NULL) { 1143 skdebug(__func__, "no PIN specified"); 1144 ret = SSH_SK_ERR_PIN_REQUIRED; 1145 goto out; 1146 } 1147 if ((metadata = fido_credman_metadata_new()) == NULL) { 1148 skdebug(__func__, "alloc failed"); 1149 goto out; 1150 } 1151 if (check_sk_options(sk->dev, "uv", &internal_uv) != 0) { 1152 skdebug(__func__, "check_sk_options failed"); 1153 goto out; 1154 } 1155 1156 if ((r = fido_credman_get_dev_metadata(sk->dev, metadata, pin)) != 0) { 1157 if (r == FIDO_ERR_INVALID_COMMAND) { 1158 skdebug(__func__, "device %s does not support " 1159 "resident keys", sk->path); 1160 ret = 0; 1161 goto out; 1162 } 1163 skdebug(__func__, "get metadata for %s failed: %s", 1164 sk->path, fido_strerr(r)); 1165 ret = fidoerr_to_skerr(r); 1166 goto out; 1167 } 1168 skdebug(__func__, "existing %llu, remaining %llu", 1169 (unsigned long long)fido_credman_rk_existing(metadata), 1170 (unsigned long long)fido_credman_rk_remaining(metadata)); 1171 if ((rp = fido_credman_rp_new()) == NULL) { 1172 skdebug(__func__, "alloc rp failed"); 1173 goto out; 1174 } 1175 if ((r = fido_credman_get_dev_rp(sk->dev, rp, pin)) != 0) { 1176 skdebug(__func__, "get RPs for %s failed: %s", 1177 sk->path, fido_strerr(r)); 1178 goto out; 1179 } 1180 nrp = fido_credman_rp_count(rp); 1181 skdebug(__func__, "Device %s has resident keys for %zu RPs", 1182 sk->path, nrp); 1183 1184 /* Iterate over RP IDs that have resident keys */ 1185 for (i = 0; i < nrp; i++) { 1186 rp_id = fido_credman_rp_id(rp, i); 1187 rp_name = fido_credman_rp_name(rp, i); 1188 skdebug(__func__, "rp %zu: name=\"%s\" id=\"%s\" hashlen=%zu", 1189 i, rp_name == NULL ? "(none)" : rp_name, 1190 rp_id == NULL ? "(none)" : rp_id, 1191 fido_credman_rp_id_hash_len(rp, i)); 1192 1193 /* Skip non-SSH RP IDs */ 1194 if (rp_id == NULL || 1195 strncasecmp(fido_credman_rp_id(rp, i), "ssh:", 4) != 0) 1196 continue; 1197 1198 fido_credman_rk_free(&rk); 1199 if ((rk = fido_credman_rk_new()) == NULL) { 1200 skdebug(__func__, "alloc rk failed"); 1201 goto out; 1202 } 1203 if ((r = fido_credman_get_dev_rk(sk->dev, 1204 fido_credman_rp_id(rp, i), rk, pin)) != 0) { 1205 skdebug(__func__, "get RKs for %s slot %zu failed: %s", 1206 sk->path, i, fido_strerr(r)); 1207 goto out; 1208 } 1209 nrk = fido_credman_rk_count(rk); 1210 skdebug(__func__, "RP \"%s\" has %zu resident keys", 1211 fido_credman_rp_id(rp, i), nrk); 1212 1213 /* Iterate over resident keys for this RP ID */ 1214 for (j = 0; j < nrk; j++) { 1215 if ((cred = fido_credman_rk(rk, j)) == NULL) { 1216 skdebug(__func__, "no RK in slot %zu", j); 1217 continue; 1218 } 1219 if ((user_name = fido_cred_user_name(cred)) == NULL) 1220 user_name = ""; 1221 user_id = fido_cred_user_id_ptr(cred); 1222 user_id_len = fido_cred_user_id_len(cred); 1223 skdebug(__func__, "Device %s RP \"%s\" user \"%s\" " 1224 "uidlen %zu slot %zu: type %d flags 0x%02x " 1225 "prot 0x%02x", sk->path, rp_id, user_name, 1226 user_id_len, j, fido_cred_type(cred), 1227 fido_cred_flags(cred), fido_cred_prot(cred)); 1228 1229 /* build response entry */ 1230 if ((srk = calloc(1, sizeof(*srk))) == NULL || 1231 (srk->key.key_handle = calloc(1, 1232 fido_cred_id_len(cred))) == NULL || 1233 (srk->application = strdup(rp_id)) == NULL || 1234 (user_id_len > 0 && 1235 (srk->user_id = calloc(1, user_id_len)) == NULL)) { 1236 skdebug(__func__, "alloc sk_resident_key"); 1237 goto out; 1238 } 1239 1240 srk->key.key_handle_len = fido_cred_id_len(cred); 1241 memcpy(srk->key.key_handle, fido_cred_id_ptr(cred), 1242 srk->key.key_handle_len); 1243 srk->user_id_len = user_id_len; 1244 if (srk->user_id_len != 0) 1245 memcpy(srk->user_id, user_id, srk->user_id_len); 1246 1247 switch (fido_cred_type(cred)) { 1248 case COSE_ES256: 1249 srk->alg = SSH_SK_ECDSA; 1250 break; 1251 case COSE_EDDSA: 1252 srk->alg = SSH_SK_ED25519; 1253 break; 1254 default: 1255 skdebug(__func__, "unsupported key type %d", 1256 fido_cred_type(cred)); 1257 goto out; /* XXX free rk and continue */ 1258 } 1259 1260 if (fido_cred_prot(cred) == FIDO_CRED_PROT_UV_REQUIRED 1261 && internal_uv == -1) 1262 srk->flags |= SSH_SK_USER_VERIFICATION_REQD; 1263 1264 if ((r = pack_public_key(srk->alg, cred, 1265 &srk->key)) != 0) { 1266 skdebug(__func__, "pack public key failed"); 1267 goto out; 1268 } 1269 /* append */ 1270 if ((tmp = recallocarray(*rksp, *nrksp, (*nrksp) + 1, 1271 sizeof(**rksp))) == NULL) { 1272 skdebug(__func__, "alloc rksp"); 1273 goto out; 1274 } 1275 *rksp = tmp; 1276 (*rksp)[(*nrksp)++] = srk; 1277 srk = NULL; 1278 } 1279 } 1280 /* Success */ 1281 ret = 0; 1282 out: 1283 if (srk != NULL) { 1284 free(srk->application); 1285 freezero(srk->key.public_key, srk->key.public_key_len); 1286 freezero(srk->key.key_handle, srk->key.key_handle_len); 1287 freezero(srk->user_id, srk->user_id_len); 1288 freezero(srk, sizeof(*srk)); 1289 } 1290 fido_credman_rp_free(&rp); 1291 fido_credman_rk_free(&rk); 1292 fido_credman_metadata_free(&metadata); 1293 return ret; 1294 } 1295 1296 int 1297 sk_load_resident_keys(const char *pin, struct sk_option **options, 1298 struct sk_resident_key ***rksp, size_t *nrksp) 1299 { 1300 int ret = SSH_SK_ERR_GENERAL, r = -1; 1301 size_t i, nrks = 0; 1302 struct sk_resident_key **rks = NULL; 1303 struct sk_usbhid *sk = NULL; 1304 char *device = NULL; 1305 1306 *rksp = NULL; 1307 *nrksp = 0; 1308 1309 fido_init(SSH_FIDO_INIT_ARG); 1310 1311 if (check_sign_load_resident_options(options, &device) != 0) 1312 goto out; /* error already logged */ 1313 if (device != NULL) 1314 sk = sk_open(device); 1315 else 1316 sk = sk_probe(NULL, NULL, 0, 1); 1317 if (sk == NULL) { 1318 ret = SSH_SK_ERR_DEVICE_NOT_FOUND; 1319 skdebug(__func__, "failed to find sk"); 1320 goto out; 1321 } 1322 skdebug(__func__, "trying %s", sk->path); 1323 if ((r = read_rks(sk, pin, &rks, &nrks)) != 0) { 1324 skdebug(__func__, "read_rks failed for %s", sk->path); 1325 ret = r; 1326 goto out; 1327 } 1328 /* success, unless we have no keys but a specific error */ 1329 if (nrks > 0 || ret == SSH_SK_ERR_GENERAL) 1330 ret = 0; 1331 *rksp = rks; 1332 *nrksp = nrks; 1333 rks = NULL; 1334 nrks = 0; 1335 out: 1336 sk_close(sk); 1337 for (i = 0; i < nrks; i++) { 1338 free(rks[i]->application); 1339 freezero(rks[i]->key.public_key, rks[i]->key.public_key_len); 1340 freezero(rks[i]->key.key_handle, rks[i]->key.key_handle_len); 1341 freezero(rks[i]->user_id, rks[i]->user_id_len); 1342 freezero(rks[i], sizeof(*rks[i])); 1343 } 1344 free(device); 1345 free(rks); 1346 return ret; 1347 } 1348 1349