=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/sk-usbhid.c,v retrieving revision 1.21 retrieving revision 1.22 diff -u -r1.21 -r1.22 --- src/usr.bin/ssh/sk-usbhid.c 2020/08/27 01:06:18 1.21 +++ src/usr.bin/ssh/sk-usbhid.c 2020/08/27 01:07:51 1.22 @@ -1,5 +1,6 @@ /* * Copyright (c) 2019 Markus Friedl + * Copyright (c) 2020 Pedro Martelletto * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -37,6 +38,7 @@ #ifndef SK_STANDALONE # include "log.h" # include "xmalloc.h" +# include "misc.h" /* * If building as part of OpenSSH, then rename exported functions. * This must be done before including sk-api.h. @@ -57,7 +59,10 @@ #define SSH_FIDO_INIT_ARG 0 #endif -#define MAX_FIDO_DEVICES 256 +#define MAX_FIDO_DEVICES 8 +#define FIDO_POLL_MS 50 +#define SELECT_MS 15000 +#define POLL_SLEEP_NS 200000000 /* Compatibility with OpenSSH 1.0.x */ #if (OPENSSL_VERSION_NUMBER < 0x10100000L) @@ -68,6 +73,11 @@ } while (0) #endif +struct sk_usbhid { + fido_dev_t *dev; + char *path; +}; + /* Return the version of the middleware API */ uint32_t sk_api_version(void); @@ -121,54 +131,185 @@ return SSH_SK_VERSION_MAJOR; } -/* Select the first identified FIDO device attached to the system */ -static char * -pick_first_device(void) +static struct sk_usbhid * +sk_open(const char *path) { - char *ret = NULL; - fido_dev_info_t *devlist = NULL; - size_t olen = 0; + struct sk_usbhid *sk; int r; - const fido_dev_info_t *di; - if ((devlist = fido_dev_info_new(1)) == NULL) { - skdebug(__func__, "fido_dev_info_new failed"); - goto out; + if (path == NULL) { + skdebug(__func__, "path == NULL"); + return NULL; } - if ((r = fido_dev_info_manifest(devlist, 1, &olen)) != FIDO_OK) { - skdebug(__func__, "fido_dev_info_manifest failed: %s", + if ((sk = calloc(1, sizeof(*sk))) == NULL) { + skdebug(__func__, "calloc sk failed"); + return NULL; + } + if ((sk->path = strdup(path)) == NULL) { + skdebug(__func__, "strdup path failed"); + free(sk); + return NULL; + } + if ((sk->dev = fido_dev_new()) == NULL) { + skdebug(__func__, "fido_dev_new failed"); + free(sk->path); + free(sk); + return NULL; + } + if ((r = fido_dev_open(sk->dev, sk->path)) != FIDO_OK) { + skdebug(__func__, "fido_dev_open %s failed: %s", sk->path, fido_strerr(r)); - goto out; + fido_dev_free(&sk->dev); + free(sk->path); + free(sk); + return NULL; } - if (olen != 1) { - skdebug(__func__, "fido_dev_info_manifest bad len %zu", olen); - goto out; + return sk; +} + +static void +sk_close(struct sk_usbhid *sk) +{ + if (sk == NULL) + return; + fido_dev_cancel(sk->dev); /* cancel any pending operation */ + fido_dev_close(sk->dev); + fido_dev_free(&sk->dev); + free(sk->path); + free(sk); +} + +static struct sk_usbhid ** +sk_openv(const fido_dev_info_t *devlist, size_t ndevs, size_t *nopen) +{ + const fido_dev_info_t *di; + struct sk_usbhid **skv; + size_t i; + + *nopen = 0; + if ((skv = calloc(ndevs, sizeof(*skv))) == NULL) { + skdebug(__func__, "calloc skv failed"); + return NULL; } - di = fido_dev_info_ptr(devlist, 0); - if ((ret = strdup(fido_dev_info_path(di))) == NULL) { - skdebug(__func__, "fido_dev_info_path failed"); - goto out; + for (i = 0; i < ndevs; i++) { + if ((di = fido_dev_info_ptr(devlist, i)) == NULL) + skdebug(__func__, "fido_dev_info_ptr failed"); + else if ((skv[*nopen] = sk_open(fido_dev_info_path(di))) == NULL) + skdebug(__func__, "sk_open failed"); + else + (*nopen)++; } - out: - fido_dev_info_free(&devlist, 1); - return ret; + if (*nopen == 0) { + for (i = 0; i < ndevs; i++) + sk_close(skv[i]); + free(skv); + skv = NULL; + } + + return skv; } -/* Check if the specified key handle exists on a given device. */ +static void +sk_closev(struct sk_usbhid **skv, size_t nsk) +{ + size_t i; + + for (i = 0; i < nsk; i++) + sk_close(skv[i]); + free(skv); +} + static int -try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len, - const char *application, const uint8_t *key_handle, size_t key_handle_len, - uint8_t flags, const char *pin) +sk_touch_begin(struct sk_usbhid **skv, size_t nsk) { + size_t i, ok = 0; + int r; + + for (i = 0; i < nsk; i++) + if ((r = fido_dev_get_touch_begin(skv[i]->dev)) != FIDO_OK) + skdebug(__func__, "fido_dev_get_touch_begin %s failed:" + " %s", skv[i]->path, fido_strerr(r)); + else + ok++; + + return ok ? 0 : -1; +} + +static int +sk_touch_poll(struct sk_usbhid **skv, size_t nsk, int *touch, size_t *idx) +{ + struct timespec ts_pause; + size_t npoll, i; + int r; + + ts_pause.tv_sec = 0; + ts_pause.tv_nsec = POLL_SLEEP_NS; + nanosleep(&ts_pause, NULL); + npoll = nsk; + for (i = 0; i < nsk; i++) { + if (skv[i] == NULL) + continue; /* device discarded */ + skdebug(__func__, "polling %s", skv[i]->path); + if ((r = fido_dev_get_touch_status(skv[i]->dev, touch, + FIDO_POLL_MS)) != FIDO_OK) { + skdebug(__func__, "fido_dev_get_touch_status %s: %s", + skv[i]->path, fido_strerr(r)); + sk_close(skv[i]); /* discard device */ + skv[i] = NULL; + if (--npoll == 0) { + skdebug(__func__, "no device left to poll"); + return -1; + } + } else if (*touch) { + *idx = i; + return 0; + } + } + *touch = 0; + return 0; +} + +/* Calculate SHA256(m) */ +static int +sha256_mem(const void *m, size_t mlen, u_char *d, size_t dlen) +{ +#ifdef WITH_OPENSSL + u_int mdlen; +#endif + + if (dlen != 32) + return -1; +#ifdef WITH_OPENSSL + mdlen = dlen; + if (!EVP_Digest(m, mlen, d, &mdlen, EVP_sha256(), NULL)) + return -1; +#else + SHA256Data(m, mlen, d); +#endif + return 0; +} + +/* Check if the specified key handle exists on a given sk. */ +static int +sk_try(const struct sk_usbhid *sk, const char *application, + const uint8_t *key_handle, size_t key_handle_len) +{ fido_assert_t *assert = NULL; + /* generate an invalid signature on FIDO2 tokens */ + const char *data = ""; + uint8_t message[32]; int r = FIDO_ERR_INTERNAL; + if (sha256_mem(data, strlen(data), message, sizeof(message)) != 0) { + skdebug(__func__, "hash message failed"); + goto out; + } if ((assert = fido_assert_new()) == NULL) { skdebug(__func__, "fido_assert_new failed"); goto out; } if ((r = fido_assert_set_clientdata_hash(assert, message, - message_len)) != FIDO_OK) { + sizeof(message))) != FIDO_OK) { skdebug(__func__, "fido_assert_set_clientdata_hash: %s", fido_strerr(r)); goto out; @@ -186,7 +327,7 @@ skdebug(__func__, "fido_assert_up: %s", fido_strerr(r)); goto out; } - r = fido_dev_get_assert(dev, assert, pin); + r = fido_dev_get_assert(sk->dev, assert, NULL); skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r)); if (r == FIDO_ERR_USER_PRESENCE_REQUIRED) { /* U2F tokens may return this */ @@ -198,77 +339,110 @@ return r != FIDO_OK ? -1 : 0; } -/* Iterate over configured devices looking for a specific key handle */ -static fido_dev_t * -find_device(const char *path, const uint8_t *message, size_t message_len, - const char *application, const uint8_t *key_handle, size_t key_handle_len, - uint8_t flags, const char *pin) +static struct sk_usbhid * +sk_select_by_cred(const fido_dev_info_t *devlist, size_t ndevs, + const char *application, const uint8_t *key_handle, size_t key_handle_len) { - fido_dev_info_t *devlist = NULL; - fido_dev_t *dev = NULL; - size_t devlist_len = 0, i; - int r; + struct sk_usbhid **skv, *sk; + size_t skvcnt, i; - if (path != NULL) { - if ((dev = fido_dev_new()) == NULL) { - skdebug(__func__, "fido_dev_new failed"); - return NULL; - } - if ((r = fido_dev_open(dev, path)) != FIDO_OK) { - skdebug(__func__, "fido_dev_open failed"); - fido_dev_free(&dev); - return NULL; - } - return dev; + if ((skv = sk_openv(devlist, ndevs, &skvcnt)) == NULL) { + skdebug(__func__, "sk_openv failed"); + return NULL; } + sk = NULL; + for (i = 0; i < skvcnt; i++) + if (sk_try(skv[i], application, key_handle, + key_handle_len) == 0) { + sk = skv[i]; + skv[i] = NULL; + skdebug(__func__, "found key in %s", sk->path); + break; + } + sk_closev(skv, skvcnt); + return sk; +} - if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) { - skdebug(__func__, "fido_dev_info_new failed"); +static struct sk_usbhid * +sk_select_by_touch(const fido_dev_info_t *devlist, size_t ndevs) +{ + struct sk_usbhid **skv, *sk; + struct timeval tv_start, tv_now, tv_delta; + size_t skvcnt, idx; + int touch, ms_remain; + + if ((skv = sk_openv(devlist, ndevs, &skvcnt)) == NULL) { + skdebug(__func__, "sk_openv failed"); + return NULL; + } + sk = NULL; + if (skvcnt < 2) { + if (skvcnt == 1) { + /* single candidate */ + sk = skv[0]; + skv[0] = NULL; + } goto out; } - if ((r = fido_dev_info_manifest(devlist, MAX_FIDO_DEVICES, - &devlist_len)) != FIDO_OK) { - skdebug(__func__, "fido_dev_info_manifest: %s", fido_strerr(r)); + if (sk_touch_begin(skv, skvcnt) == -1) { + skdebug(__func__, "sk_touch_begin failed"); goto out; } - - skdebug(__func__, "found %zu device(s)", devlist_len); - - for (i = 0; i < devlist_len; i++) { - const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i); - - if (di == NULL) { - skdebug(__func__, "fido_dev_info_ptr %zu failed", i); - continue; + monotime_tv(&tv_start); + do { + if (sk_touch_poll(skv, skvcnt, &touch, &idx) == -1) { + skdebug(__func__, "sk_touch_poll failed"); + goto out; } - if ((path = fido_dev_info_path(di)) == NULL) { - skdebug(__func__, "fido_dev_info_path %zu failed", i); - continue; + if (touch) { + sk = skv[idx]; + skv[idx] = NULL; + goto out; } - skdebug(__func__, "trying device %zu: %s", i, path); - if ((dev = fido_dev_new()) == NULL) { - skdebug(__func__, "fido_dev_new failed"); - continue; - } - if ((r = fido_dev_open(dev, path)) != FIDO_OK) { - skdebug(__func__, "fido_dev_open failed"); - fido_dev_free(&dev); - continue; - } - if (try_device(dev, message, message_len, application, - key_handle, key_handle_len, flags, pin) == 0) { - skdebug(__func__, "found key"); - break; - } - fido_dev_close(dev); - fido_dev_free(&dev); - } + monotime_tv(&tv_now); + timersub(&tv_now, &tv_start, &tv_delta); + ms_remain = SELECT_MS - tv_delta.tv_sec * 1000 - + tv_delta.tv_usec / 1000; + } while (ms_remain >= FIDO_POLL_MS); + skdebug(__func__, "timeout"); +out: + sk_closev(skv, skvcnt); + return sk; +} - out: - if (devlist != NULL) - fido_dev_info_free(&devlist, MAX_FIDO_DEVICES); +static struct sk_usbhid * +sk_probe(const char *application, const uint8_t *key_handle, + size_t key_handle_len) +{ + struct sk_usbhid *sk; + fido_dev_info_t *devlist; + size_t ndevs; + int r; - return dev; + if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) { + skdebug(__func__, "fido_dev_info_new failed"); + return NULL; + } + if ((r = fido_dev_info_manifest(devlist, MAX_FIDO_DEVICES, + &ndevs)) != FIDO_OK) { + skdebug(__func__, "fido_dev_info_manifest failed: %s", + fido_strerr(r)); + fido_dev_info_free(&devlist, MAX_FIDO_DEVICES); + return NULL; + } + skdebug(__func__, "%zu device(s) detected", ndevs); + if (ndevs == 0) { + sk = NULL; + } else if (application != NULL && key_handle != NULL) { + skdebug(__func__, "selecting sk by cred"); + sk = sk_select_by_cred(devlist, ndevs, application, key_handle, + key_handle_len); + } else { + skdebug(__func__, "selecting sk by touch"); + sk = sk_select_by_touch(devlist, ndevs); + } + fido_dev_info_free(&devlist, MAX_FIDO_DEVICES); + return sk; } #ifdef WITH_OPENSSL @@ -445,52 +619,15 @@ return 0; } -static int -check_sk_extensions(fido_dev_t *dev, const char *ext, int *ret) -{ - fido_cbor_info_t *info; - char * const *ptr; - size_t len, i; - int r; - - *ret = 0; - - if (!fido_dev_is_fido2(dev)) { - skdebug(__func__, "device is not fido2"); - return 0; - } - if ((info = fido_cbor_info_new()) == NULL) { - skdebug(__func__, "fido_cbor_info_new failed"); - return -1; - } - if ((r = fido_dev_get_cbor_info(dev, info)) != FIDO_OK) { - skdebug(__func__, "fido_dev_get_cbor_info: %s", fido_strerr(r)); - fido_cbor_info_free(&info); - return -1; - } - ptr = fido_cbor_info_extensions_ptr(info); - len = fido_cbor_info_extensions_len(info); - for (i = 0; i < len; i++) { - if (!strcmp(ptr[i], ext)) { - *ret = 1; - break; - } - } - fido_cbor_info_free(&info); - skdebug(__func__, "extension %s %s", ext, *ret ? "present" : "absent"); - - return 0; -} - int sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, const char *application, uint8_t flags, const char *pin, struct sk_option **options, struct sk_enroll_response **enroll_response) { fido_cred_t *cred = NULL; - fido_dev_t *dev = NULL; const uint8_t *ptr; uint8_t user_id[32]; + struct sk_usbhid *sk = NULL; struct sk_enroll_response *response = NULL; size_t len; int credprot; @@ -505,12 +642,12 @@ skdebug(__func__, "enroll_response == NULL"); goto out; } + *enroll_response = NULL; memset(user_id, 0, sizeof(user_id)); - if (check_enroll_options(options, &device, - user_id, sizeof(user_id)) != 0) + if (check_enroll_options(options, &device, user_id, + sizeof(user_id)) != 0) goto out; /* error already logged */ - *enroll_response = NULL; switch(alg) { #ifdef WITH_OPENSSL case SSH_SK_ECDSA: @@ -524,12 +661,15 @@ skdebug(__func__, "unsupported key type %d", alg); goto out; } - if (device == NULL && (device = pick_first_device()) == NULL) { - ret = SSH_SK_ERR_DEVICE_NOT_FOUND; - skdebug(__func__, "pick_first_device failed"); + if (device != NULL) + sk = sk_open(device); + else + sk = sk_probe(NULL, NULL, 0); + if (sk == NULL) { + skdebug(__func__, "failed to find sk"); goto out; } - skdebug(__func__, "using device %s", device); + skdebug(__func__, "using device %s", sk->path); if ((cred = fido_cred_new()) == NULL) { skdebug(__func__, "fido_cred_new failed"); goto out; @@ -558,22 +698,11 @@ skdebug(__func__, "fido_cred_set_rp: %s", fido_strerr(r)); goto out; } - if ((dev = fido_dev_new()) == NULL) { - skdebug(__func__, "fido_dev_new failed"); - goto out; - } - if ((r = fido_dev_open(dev, device)) != FIDO_OK) { - skdebug(__func__, "fido_dev_open: %s", fido_strerr(r)); - goto out; - } if ((flags & (SSH_SK_RESIDENT_KEY|SSH_SK_USER_VERIFICATION_REQD)) != 0) { - if (check_sk_extensions(dev, "credProtect", &credprot) < 0) { - skdebug(__func__, "check_sk_extensions failed"); - goto out; - } - if (credprot == 0) { - skdebug(__func__, "refusing to create unprotected " - "resident/verify-required key"); + if (!fido_dev_supports_cred_prot(sk->dev)) { + skdebug(__func__, "%s does not support credprot, " + "refusing to create unprotected " + "resident/verify-required key", sk->path); ret = SSH_SK_ERR_UNSUPPORTED; goto out; } @@ -589,7 +718,7 @@ goto out; } } - if ((r = fido_dev_make_cred(dev, cred, pin)) != FIDO_OK) { + if ((r = fido_dev_make_cred(sk->dev, cred, pin)) != FIDO_OK) { skdebug(__func__, "fido_dev_make_cred: %s", fido_strerr(r)); ret = fidoerr_to_skerr(r); goto out; @@ -656,13 +785,8 @@ free(response->attestation_cert); free(response); } - if (dev != NULL) { - fido_dev_close(dev); - fido_dev_free(&dev); - } - if (cred != NULL) { - fido_cred_free(&cred); - } + sk_close(sk); + fido_cred_free(&cred); return ret; } @@ -776,26 +900,6 @@ return 0; } -/* Calculate SHA256(m) */ -static int -sha256_mem(const void *m, size_t mlen, u_char *d, size_t dlen) -{ -#ifdef WITH_OPENSSL - u_int mdlen; -#endif - - if (dlen != 32) - return -1; -#ifdef WITH_OPENSSL - mdlen = dlen; - if (!EVP_Digest(m, mlen, d, &mdlen, EVP_sha256(), NULL)) - return -1; -#else - SHA256Data(m, mlen, d); -#endif - return 0; -} - int sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, const char *application, @@ -805,7 +909,7 @@ { fido_assert_t *assert = NULL; char *device = NULL; - fido_dev_t *dev = NULL; + struct sk_usbhid *sk = NULL; struct sk_sign_response *response = NULL; uint8_t message[32]; int ret = SSH_SK_ERR_GENERAL; @@ -825,9 +929,14 @@ skdebug(__func__, "hash message failed"); goto out; } - if ((dev = find_device(device, message, sizeof(message), - application, key_handle, key_handle_len, flags, pin)) == NULL) { - skdebug(__func__, "couldn't find device for key handle"); + if (device != NULL) + sk = sk_open(device); + else if (pin != NULL || (flags & SSH_SK_USER_VERIFICATION_REQD)) + sk = sk_probe(NULL, NULL, 0); + else + sk = sk_probe(application, key_handle, key_handle_len); + if (sk == NULL) { + skdebug(__func__, "failed to find sk"); goto out; } if ((assert = fido_assert_new()) == NULL) { @@ -861,7 +970,7 @@ ret = FIDO_ERR_PIN_REQUIRED; goto out; } - if ((r = fido_dev_get_assert(dev, assert, pin)) != FIDO_OK) { + if ((r = fido_dev_get_assert(sk->dev, assert, pin)) != FIDO_OK) { skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r)); ret = fidoerr_to_skerr(r); goto out; @@ -887,22 +996,16 @@ free(response->sig_s); free(response); } - if (dev != NULL) { - fido_dev_close(dev); - fido_dev_free(&dev); - } - if (assert != NULL) { - fido_assert_free(&assert); - } + sk_close(sk); + fido_assert_free(&assert); return ret; } static int -read_rks(const char *devpath, const char *pin, +read_rks(struct sk_usbhid *sk, const char *pin, struct sk_resident_key ***rksp, size_t *nrksp) { int ret = SSH_SK_ERR_GENERAL, r = -1; - fido_dev_t *dev = NULL; fido_credman_metadata_t *metadata = NULL; fido_credman_rp_t *rp = NULL; fido_credman_rk_t *rk = NULL; @@ -910,30 +1013,25 @@ const fido_cred_t *cred; struct sk_resident_key *srk = NULL, **tmp; - if ((dev = fido_dev_new()) == NULL) { - skdebug(__func__, "fido_dev_new failed"); - return ret; + if (pin == NULL) { + skdebug(__func__, "no PIN specified"); + ret = SSH_SK_ERR_PIN_REQUIRED; + goto out; } - if ((r = fido_dev_open(dev, devpath)) != FIDO_OK) { - skdebug(__func__, "fido_dev_open %s failed: %s", - devpath, fido_strerr(r)); - fido_dev_free(&dev); - return ret; - } if ((metadata = fido_credman_metadata_new()) == NULL) { skdebug(__func__, "alloc failed"); goto out; } - if ((r = fido_credman_get_dev_metadata(dev, metadata, pin)) != 0) { + if ((r = fido_credman_get_dev_metadata(sk->dev, metadata, pin)) != 0) { if (r == FIDO_ERR_INVALID_COMMAND) { skdebug(__func__, "device %s does not support " - "resident keys", devpath); + "resident keys", sk->path); ret = 0; goto out; } skdebug(__func__, "get metadata for %s failed: %s", - devpath, fido_strerr(r)); + sk->path, fido_strerr(r)); ret = fidoerr_to_skerr(r); goto out; } @@ -944,14 +1042,14 @@ skdebug(__func__, "alloc rp failed"); goto out; } - if ((r = fido_credman_get_dev_rp(dev, rp, pin)) != 0) { + if ((r = fido_credman_get_dev_rp(sk->dev, rp, pin)) != 0) { skdebug(__func__, "get RPs for %s failed: %s", - devpath, fido_strerr(r)); + sk->path, fido_strerr(r)); goto out; } nrp = fido_credman_rp_count(rp); skdebug(__func__, "Device %s has resident keys for %zu RPs", - devpath, nrp); + sk->path, nrp); /* Iterate over RP IDs that have resident keys */ for (i = 0; i < nrp; i++) { @@ -968,10 +1066,10 @@ skdebug(__func__, "alloc rk failed"); goto out; } - if ((r = fido_credman_get_dev_rk(dev, fido_credman_rp_id(rp, i), - rk, pin)) != 0) { + if ((r = fido_credman_get_dev_rk(sk->dev, + fido_credman_rp_id(rp, i), rk, pin)) != 0) { skdebug(__func__, "get RKs for %s slot %zu failed: %s", - devpath, i, fido_strerr(r)); + sk->path, i, fido_strerr(r)); goto out; } nrk = fido_credman_rk_count(rk); @@ -985,7 +1083,7 @@ continue; } skdebug(__func__, "Device %s RP \"%s\" slot %zu: " - "type %d flags 0x%02x prot 0x%02x", devpath, + "type %d flags 0x%02x prot 0x%02x", sk->path, fido_credman_rp_id(rp, i), j, fido_cred_type(cred), fido_cred_flags(cred), fido_cred_prot(cred)); @@ -1044,8 +1142,6 @@ } fido_credman_rp_free(&rp); fido_credman_rk_free(&rk); - fido_dev_close(dev); - fido_dev_free(&dev); fido_credman_metadata_free(&metadata); return ret; } @@ -1055,11 +1151,11 @@ struct sk_resident_key ***rksp, size_t *nrksp) { int ret = SSH_SK_ERR_GENERAL, r = -1; - fido_dev_info_t *devlist = NULL; - size_t i, ndev = 0, nrks = 0; - const fido_dev_info_t *di; + size_t i, nrks = 0; struct sk_resident_key **rks = NULL; + struct sk_usbhid *sk = NULL; char *device = NULL; + *rksp = NULL; *nrksp = 0; @@ -1067,41 +1163,20 @@ if (check_sign_load_resident_options(options, &device) != 0) goto out; /* error already logged */ - if (device != NULL) { - skdebug(__func__, "trying %s", device); - if ((r = read_rks(device, pin, &rks, &nrks)) != 0) { - skdebug(__func__, "read_rks failed for %s", device); - ret = r; - goto out; - } - } else { - /* Try all devices */ - if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) { - skdebug(__func__, "fido_dev_info_new failed"); - goto out; - } - if ((r = fido_dev_info_manifest(devlist, - MAX_FIDO_DEVICES, &ndev)) != FIDO_OK) { - skdebug(__func__, "fido_dev_info_manifest failed: %s", - fido_strerr(r)); - goto out; - } - for (i = 0; i < ndev; i++) { - if ((di = fido_dev_info_ptr(devlist, i)) == NULL) { - skdebug(__func__, "no dev info at %zu", i); - continue; - } - skdebug(__func__, "trying %s", fido_dev_info_path(di)); - if ((r = read_rks(fido_dev_info_path(di), pin, - &rks, &nrks)) != 0) { - skdebug(__func__, "read_rks failed for %s", - fido_dev_info_path(di)); - /* remember last error */ - ret = r; - continue; - } - } + if (device != NULL) + sk = sk_open(device); + else + sk = sk_probe(NULL, NULL, 0); + if (sk == NULL) { + skdebug(__func__, "failed to find sk"); + goto out; } + skdebug(__func__, "trying %s", sk->path); + if ((r = read_rks(sk, pin, &rks, &nrks)) != 0) { + skdebug(__func__, "read_rks failed for %s", sk->path); + ret = r; + goto out; + } /* success, unless we have no keys but a specific error */ if (nrks > 0 || ret == SSH_SK_ERR_GENERAL) ret = 0; @@ -1110,7 +1185,7 @@ rks = NULL; nrks = 0; out: - free(device); + sk_close(sk); for (i = 0; i < nrks; i++) { free(rks[i]->application); freezero(rks[i]->key.public_key, rks[i]->key.public_key_len); @@ -1118,7 +1193,6 @@ freezero(rks[i], sizeof(*rks[i])); } free(rks); - fido_dev_info_free(&devlist, MAX_FIDO_DEVICES); return ret; }