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