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