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