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