diff options
Diffstat (limited to 'sk-usbhid.c')
-rw-r--r-- | sk-usbhid.c | 626 |
1 files changed, 416 insertions, 210 deletions
diff --git a/sk-usbhid.c b/sk-usbhid.c index 25250824d..007c59644 100644 --- a/sk-usbhid.c +++ b/sk-usbhid.c | |||
@@ -1,5 +1,7 @@ | |||
1 | /* $OpenBSD: sk-usbhid.c,v 1.26 2020/09/09 03:08:01 djm Exp $ */ | ||
1 | /* | 2 | /* |
2 | * Copyright (c) 2019 Markus Friedl | 3 | * Copyright (c) 2019 Markus Friedl |
4 | * Copyright (c) 2020 Pedro Martelletto | ||
3 | * | 5 | * |
4 | * Permission to use, copy, modify, and distribute this software for any | 6 | * Permission to use, copy, modify, and distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above | 7 | * purpose with or without fee is hereby granted, provided that the above |
@@ -40,9 +42,33 @@ | |||
40 | #include <fido.h> | 42 | #include <fido.h> |
41 | #include <fido/credman.h> | 43 | #include <fido/credman.h> |
42 | 44 | ||
45 | /* backwards compat for libfido2 */ | ||
46 | #ifndef HAVE_FIDO_CRED_PROT | ||
47 | #define fido_cred_prot(x) (0) | ||
48 | #endif | ||
49 | #ifndef HAVE_FIDO_CRED_SET_PROT | ||
50 | #define fido_cred_set_prot(x, y) (FIDO_ERR_UNSUPPORTED_OPTION) | ||
51 | #endif | ||
52 | #ifndef HAVE_FIDO_DEV_SUPPORTS_CRED_PROT | ||
53 | #define fido_dev_supports_cred_prot(x) (0) | ||
54 | #endif | ||
55 | #ifndef HAVE_FIDO_DEV_GET_TOUCH_BEGIN | ||
56 | #define fido_dev_get_touch_begin(x) (FIDO_ERR_UNSUPPORTED_OPTION) | ||
57 | #endif | ||
58 | #ifndef HAVE_FIDO_DEV_GET_TOUCH_STATUS | ||
59 | #define fido_dev_get_touch_status(x, y, z) (FIDO_ERR_UNSUPPORTED_OPTION) | ||
60 | #endif | ||
61 | #ifndef FIDO_CRED_PROT_UV_REQUIRED | ||
62 | #define FIDO_CRED_PROT_UV_REQUIRED 0 | ||
63 | #endif | ||
64 | #ifndef FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID | ||
65 | #define FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID 0 | ||
66 | #endif | ||
67 | |||
43 | #ifndef SK_STANDALONE | 68 | #ifndef SK_STANDALONE |
44 | # include "log.h" | 69 | # include "log.h" |
45 | # include "xmalloc.h" | 70 | # include "xmalloc.h" |
71 | # include "misc.h" | ||
46 | /* | 72 | /* |
47 | * If building as part of OpenSSH, then rename exported functions. | 73 | * If building as part of OpenSSH, then rename exported functions. |
48 | * This must be done before including sk-api.h. | 74 | * This must be done before including sk-api.h. |
@@ -57,7 +83,16 @@ | |||
57 | 83 | ||
58 | /* #define SK_DEBUG 1 */ | 84 | /* #define SK_DEBUG 1 */ |
59 | 85 | ||
60 | #define MAX_FIDO_DEVICES 256 | 86 | #ifdef SK_DEBUG |
87 | #define SSH_FIDO_INIT_ARG FIDO_DEBUG | ||
88 | #else | ||
89 | #define SSH_FIDO_INIT_ARG 0 | ||
90 | #endif | ||
91 | |||
92 | #define MAX_FIDO_DEVICES 8 | ||
93 | #define FIDO_POLL_MS 50 | ||
94 | #define SELECT_MS 15000 | ||
95 | #define POLL_SLEEP_NS 200000000 | ||
61 | 96 | ||
62 | /* Compatibility with OpenSSH 1.0.x */ | 97 | /* Compatibility with OpenSSH 1.0.x */ |
63 | #if (OPENSSL_VERSION_NUMBER < 0x10100000L) | 98 | #if (OPENSSL_VERSION_NUMBER < 0x10100000L) |
@@ -68,6 +103,11 @@ | |||
68 | } while (0) | 103 | } while (0) |
69 | #endif | 104 | #endif |
70 | 105 | ||
106 | struct sk_usbhid { | ||
107 | fido_dev_t *dev; | ||
108 | char *path; | ||
109 | }; | ||
110 | |||
71 | /* Return the version of the middleware API */ | 111 | /* Return the version of the middleware API */ |
72 | uint32_t sk_api_version(void); | 112 | uint32_t sk_api_version(void); |
73 | 113 | ||
@@ -121,53 +161,185 @@ sk_api_version(void) | |||
121 | return SSH_SK_VERSION_MAJOR; | 161 | return SSH_SK_VERSION_MAJOR; |
122 | } | 162 | } |
123 | 163 | ||
124 | /* Select the first identified FIDO device attached to the system */ | 164 | static struct sk_usbhid * |
125 | static char * | 165 | sk_open(const char *path) |
126 | pick_first_device(void) | ||
127 | { | 166 | { |
128 | char *ret = NULL; | 167 | struct sk_usbhid *sk; |
129 | fido_dev_info_t *devlist = NULL; | ||
130 | size_t olen = 0; | ||
131 | int r; | 168 | int r; |
132 | const fido_dev_info_t *di; | ||
133 | 169 | ||
134 | if ((devlist = fido_dev_info_new(1)) == NULL) { | 170 | if (path == NULL) { |
135 | skdebug(__func__, "fido_dev_info_new failed"); | 171 | skdebug(__func__, "path == NULL"); |
136 | goto out; | 172 | return NULL; |
137 | } | 173 | } |
138 | if ((r = fido_dev_info_manifest(devlist, 1, &olen)) != FIDO_OK) { | 174 | if ((sk = calloc(1, sizeof(*sk))) == NULL) { |
139 | skdebug(__func__, "fido_dev_info_manifest failed: %s", | 175 | skdebug(__func__, "calloc sk failed"); |
176 | return NULL; | ||
177 | } | ||
178 | if ((sk->path = strdup(path)) == NULL) { | ||
179 | skdebug(__func__, "strdup path failed"); | ||
180 | free(sk); | ||
181 | return NULL; | ||
182 | } | ||
183 | if ((sk->dev = fido_dev_new()) == NULL) { | ||
184 | skdebug(__func__, "fido_dev_new failed"); | ||
185 | free(sk->path); | ||
186 | free(sk); | ||
187 | return NULL; | ||
188 | } | ||
189 | if ((r = fido_dev_open(sk->dev, sk->path)) != FIDO_OK) { | ||
190 | skdebug(__func__, "fido_dev_open %s failed: %s", sk->path, | ||
140 | fido_strerr(r)); | 191 | fido_strerr(r)); |
141 | goto out; | 192 | fido_dev_free(&sk->dev); |
193 | free(sk->path); | ||
194 | free(sk); | ||
195 | return NULL; | ||
142 | } | 196 | } |
143 | if (olen != 1) { | 197 | return sk; |
144 | skdebug(__func__, "fido_dev_info_manifest bad len %zu", olen); | 198 | } |
145 | goto out; | 199 | |
200 | static void | ||
201 | sk_close(struct sk_usbhid *sk) | ||
202 | { | ||
203 | if (sk == NULL) | ||
204 | return; | ||
205 | fido_dev_cancel(sk->dev); /* cancel any pending operation */ | ||
206 | fido_dev_close(sk->dev); | ||
207 | fido_dev_free(&sk->dev); | ||
208 | free(sk->path); | ||
209 | free(sk); | ||
210 | } | ||
211 | |||
212 | static struct sk_usbhid ** | ||
213 | sk_openv(const fido_dev_info_t *devlist, size_t ndevs, size_t *nopen) | ||
214 | { | ||
215 | const fido_dev_info_t *di; | ||
216 | struct sk_usbhid **skv; | ||
217 | size_t i; | ||
218 | |||
219 | *nopen = 0; | ||
220 | if ((skv = calloc(ndevs, sizeof(*skv))) == NULL) { | ||
221 | skdebug(__func__, "calloc skv failed"); | ||
222 | return NULL; | ||
146 | } | 223 | } |
147 | di = fido_dev_info_ptr(devlist, 0); | 224 | for (i = 0; i < ndevs; i++) { |
148 | if ((ret = strdup(fido_dev_info_path(di))) == NULL) { | 225 | if ((di = fido_dev_info_ptr(devlist, i)) == NULL) |
149 | skdebug(__func__, "fido_dev_info_path failed"); | 226 | skdebug(__func__, "fido_dev_info_ptr failed"); |
150 | goto out; | 227 | else if ((skv[*nopen] = sk_open(fido_dev_info_path(di))) == NULL) |
228 | skdebug(__func__, "sk_open failed"); | ||
229 | else | ||
230 | (*nopen)++; | ||
151 | } | 231 | } |
152 | out: | 232 | if (*nopen == 0) { |
153 | fido_dev_info_free(&devlist, 1); | 233 | for (i = 0; i < ndevs; i++) |
154 | return ret; | 234 | sk_close(skv[i]); |
235 | free(skv); | ||
236 | skv = NULL; | ||
237 | } | ||
238 | |||
239 | return skv; | ||
240 | } | ||
241 | |||
242 | static void | ||
243 | sk_closev(struct sk_usbhid **skv, size_t nsk) | ||
244 | { | ||
245 | size_t i; | ||
246 | |||
247 | for (i = 0; i < nsk; i++) | ||
248 | sk_close(skv[i]); | ||
249 | free(skv); | ||
155 | } | 250 | } |
156 | 251 | ||
157 | /* Check if the specified key handle exists on a given device. */ | ||
158 | static int | 252 | static int |
159 | try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len, | 253 | sk_touch_begin(struct sk_usbhid **skv, size_t nsk) |
160 | const char *application, const uint8_t *key_handle, size_t key_handle_len) | 254 | { |
255 | size_t i, ok = 0; | ||
256 | int r; | ||
257 | |||
258 | for (i = 0; i < nsk; i++) | ||
259 | if ((r = fido_dev_get_touch_begin(skv[i]->dev)) != FIDO_OK) | ||
260 | skdebug(__func__, "fido_dev_get_touch_begin %s failed:" | ||
261 | " %s", skv[i]->path, fido_strerr(r)); | ||
262 | else | ||
263 | ok++; | ||
264 | |||
265 | return ok ? 0 : -1; | ||
266 | } | ||
267 | |||
268 | static int | ||
269 | sk_touch_poll(struct sk_usbhid **skv, size_t nsk, int *touch, size_t *idx) | ||
270 | { | ||
271 | struct timespec ts_pause; | ||
272 | size_t npoll, i; | ||
273 | int r; | ||
274 | |||
275 | ts_pause.tv_sec = 0; | ||
276 | ts_pause.tv_nsec = POLL_SLEEP_NS; | ||
277 | nanosleep(&ts_pause, NULL); | ||
278 | npoll = nsk; | ||
279 | for (i = 0; i < nsk; i++) { | ||
280 | if (skv[i] == NULL) | ||
281 | continue; /* device discarded */ | ||
282 | skdebug(__func__, "polling %s", skv[i]->path); | ||
283 | if ((r = fido_dev_get_touch_status(skv[i]->dev, touch, | ||
284 | FIDO_POLL_MS)) != FIDO_OK) { | ||
285 | skdebug(__func__, "fido_dev_get_touch_status %s: %s", | ||
286 | skv[i]->path, fido_strerr(r)); | ||
287 | sk_close(skv[i]); /* discard device */ | ||
288 | skv[i] = NULL; | ||
289 | if (--npoll == 0) { | ||
290 | skdebug(__func__, "no device left to poll"); | ||
291 | return -1; | ||
292 | } | ||
293 | } else if (*touch) { | ||
294 | *idx = i; | ||
295 | return 0; | ||
296 | } | ||
297 | } | ||
298 | *touch = 0; | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | /* Calculate SHA256(m) */ | ||
303 | static int | ||
304 | sha256_mem(const void *m, size_t mlen, u_char *d, size_t dlen) | ||
305 | { | ||
306 | #ifdef WITH_OPENSSL | ||
307 | u_int mdlen; | ||
308 | #endif | ||
309 | |||
310 | if (dlen != 32) | ||
311 | return -1; | ||
312 | #ifdef WITH_OPENSSL | ||
313 | mdlen = dlen; | ||
314 | if (!EVP_Digest(m, mlen, d, &mdlen, EVP_sha256(), NULL)) | ||
315 | return -1; | ||
316 | #else | ||
317 | SHA256Data(m, mlen, d); | ||
318 | #endif | ||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | /* Check if the specified key handle exists on a given sk. */ | ||
323 | static int | ||
324 | sk_try(const struct sk_usbhid *sk, const char *application, | ||
325 | const uint8_t *key_handle, size_t key_handle_len) | ||
161 | { | 326 | { |
162 | fido_assert_t *assert = NULL; | 327 | fido_assert_t *assert = NULL; |
328 | /* generate an invalid signature on FIDO2 tokens */ | ||
329 | const char *data = ""; | ||
330 | uint8_t message[32]; | ||
163 | int r = FIDO_ERR_INTERNAL; | 331 | int r = FIDO_ERR_INTERNAL; |
164 | 332 | ||
333 | if (sha256_mem(data, strlen(data), message, sizeof(message)) != 0) { | ||
334 | skdebug(__func__, "hash message failed"); | ||
335 | goto out; | ||
336 | } | ||
165 | if ((assert = fido_assert_new()) == NULL) { | 337 | if ((assert = fido_assert_new()) == NULL) { |
166 | skdebug(__func__, "fido_assert_new failed"); | 338 | skdebug(__func__, "fido_assert_new failed"); |
167 | goto out; | 339 | goto out; |
168 | } | 340 | } |
169 | if ((r = fido_assert_set_clientdata_hash(assert, message, | 341 | if ((r = fido_assert_set_clientdata_hash(assert, message, |
170 | message_len)) != FIDO_OK) { | 342 | sizeof(message))) != FIDO_OK) { |
171 | skdebug(__func__, "fido_assert_set_clientdata_hash: %s", | 343 | skdebug(__func__, "fido_assert_set_clientdata_hash: %s", |
172 | fido_strerr(r)); | 344 | fido_strerr(r)); |
173 | goto out; | 345 | goto out; |
@@ -185,7 +357,7 @@ try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len, | |||
185 | skdebug(__func__, "fido_assert_up: %s", fido_strerr(r)); | 357 | skdebug(__func__, "fido_assert_up: %s", fido_strerr(r)); |
186 | goto out; | 358 | goto out; |
187 | } | 359 | } |
188 | r = fido_dev_get_assert(dev, assert, NULL); | 360 | r = fido_dev_get_assert(sk->dev, assert, NULL); |
189 | skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r)); | 361 | skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r)); |
190 | if (r == FIDO_ERR_USER_PRESENCE_REQUIRED) { | 362 | if (r == FIDO_ERR_USER_PRESENCE_REQUIRED) { |
191 | /* U2F tokens may return this */ | 363 | /* U2F tokens may return this */ |
@@ -197,76 +369,122 @@ try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len, | |||
197 | return r != FIDO_OK ? -1 : 0; | 369 | return r != FIDO_OK ? -1 : 0; |
198 | } | 370 | } |
199 | 371 | ||
200 | /* Iterate over configured devices looking for a specific key handle */ | 372 | static struct sk_usbhid * |
201 | static fido_dev_t * | 373 | sk_select_by_cred(const fido_dev_info_t *devlist, size_t ndevs, |
202 | find_device(const char *path, const uint8_t *message, size_t message_len, | ||
203 | const char *application, const uint8_t *key_handle, size_t key_handle_len) | 374 | const char *application, const uint8_t *key_handle, size_t key_handle_len) |
204 | { | 375 | { |
205 | fido_dev_info_t *devlist = NULL; | 376 | struct sk_usbhid **skv, *sk; |
206 | fido_dev_t *dev = NULL; | 377 | size_t skvcnt, i; |
207 | size_t devlist_len = 0, i; | ||
208 | int r; | ||
209 | 378 | ||
210 | if (path != NULL) { | 379 | if ((skv = sk_openv(devlist, ndevs, &skvcnt)) == NULL) { |
211 | if ((dev = fido_dev_new()) == NULL) { | 380 | skdebug(__func__, "sk_openv failed"); |
212 | skdebug(__func__, "fido_dev_new failed"); | 381 | return NULL; |
213 | return NULL; | 382 | } |
214 | } | 383 | if (skvcnt == 1) { |
215 | if ((r = fido_dev_open(dev, path)) != FIDO_OK) { | 384 | sk = skv[0]; |
216 | skdebug(__func__, "fido_dev_open failed"); | 385 | skv[0] = NULL; |
217 | fido_dev_free(&dev); | 386 | goto out; |
218 | return NULL; | 387 | } |
388 | sk = NULL; | ||
389 | for (i = 0; i < skvcnt; i++) { | ||
390 | if (sk_try(skv[i], application, key_handle, | ||
391 | key_handle_len) == 0) { | ||
392 | sk = skv[i]; | ||
393 | skv[i] = NULL; | ||
394 | skdebug(__func__, "found key in %s", sk->path); | ||
395 | break; | ||
219 | } | 396 | } |
220 | return dev; | ||
221 | } | 397 | } |
398 | out: | ||
399 | sk_closev(skv, skvcnt); | ||
400 | return sk; | ||
401 | } | ||
222 | 402 | ||
223 | if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) { | 403 | static struct sk_usbhid * |
224 | skdebug(__func__, "fido_dev_info_new failed"); | 404 | sk_select_by_touch(const fido_dev_info_t *devlist, size_t ndevs) |
405 | { | ||
406 | struct sk_usbhid **skv, *sk; | ||
407 | struct timeval tv_start, tv_now, tv_delta; | ||
408 | size_t skvcnt, idx; | ||
409 | int touch, ms_remain; | ||
410 | |||
411 | if ((skv = sk_openv(devlist, ndevs, &skvcnt)) == NULL) { | ||
412 | skdebug(__func__, "sk_openv failed"); | ||
413 | return NULL; | ||
414 | } | ||
415 | sk = NULL; | ||
416 | if (skvcnt < 2) { | ||
417 | if (skvcnt == 1) { | ||
418 | /* single candidate */ | ||
419 | sk = skv[0]; | ||
420 | skv[0] = NULL; | ||
421 | } | ||
225 | goto out; | 422 | goto out; |
226 | } | 423 | } |
227 | if ((r = fido_dev_info_manifest(devlist, MAX_FIDO_DEVICES, | 424 | #ifndef HAVE_FIDO_DEV_GET_TOUCH_STATUS |
228 | &devlist_len)) != FIDO_OK) { | 425 | skdebug(__func__, "libfido2 version does not support a feature needed for multiple tokens. Please upgrade to >=1.5.0"); |
229 | skdebug(__func__, "fido_dev_info_manifest: %s", fido_strerr(r)); | 426 | goto out; |
427 | #endif | ||
428 | |||
429 | if (sk_touch_begin(skv, skvcnt) == -1) { | ||
430 | skdebug(__func__, "sk_touch_begin failed"); | ||
230 | goto out; | 431 | goto out; |
231 | } | 432 | } |
232 | 433 | monotime_tv(&tv_start); | |
233 | skdebug(__func__, "found %zu device(s)", devlist_len); | 434 | do { |
234 | 435 | if (sk_touch_poll(skv, skvcnt, &touch, &idx) == -1) { | |
235 | for (i = 0; i < devlist_len; i++) { | 436 | skdebug(__func__, "sk_touch_poll failed"); |
236 | const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i); | 437 | goto out; |
237 | |||
238 | if (di == NULL) { | ||
239 | skdebug(__func__, "fido_dev_info_ptr %zu failed", i); | ||
240 | continue; | ||
241 | } | ||
242 | if ((path = fido_dev_info_path(di)) == NULL) { | ||
243 | skdebug(__func__, "fido_dev_info_path %zu failed", i); | ||
244 | continue; | ||
245 | } | ||
246 | skdebug(__func__, "trying device %zu: %s", i, path); | ||
247 | if ((dev = fido_dev_new()) == NULL) { | ||
248 | skdebug(__func__, "fido_dev_new failed"); | ||
249 | continue; | ||
250 | } | ||
251 | if ((r = fido_dev_open(dev, path)) != FIDO_OK) { | ||
252 | skdebug(__func__, "fido_dev_open failed"); | ||
253 | fido_dev_free(&dev); | ||
254 | continue; | ||
255 | } | 438 | } |
256 | if (try_device(dev, message, message_len, application, | 439 | if (touch) { |
257 | key_handle, key_handle_len) == 0) { | 440 | sk = skv[idx]; |
258 | skdebug(__func__, "found key"); | 441 | skv[idx] = NULL; |
259 | break; | 442 | goto out; |
260 | } | 443 | } |
261 | fido_dev_close(dev); | 444 | monotime_tv(&tv_now); |
262 | fido_dev_free(&dev); | 445 | timersub(&tv_now, &tv_start, &tv_delta); |
263 | } | 446 | ms_remain = SELECT_MS - tv_delta.tv_sec * 1000 - |
447 | tv_delta.tv_usec / 1000; | ||
448 | } while (ms_remain >= FIDO_POLL_MS); | ||
449 | skdebug(__func__, "timeout"); | ||
450 | out: | ||
451 | sk_closev(skv, skvcnt); | ||
452 | return sk; | ||
453 | } | ||
264 | 454 | ||
265 | out: | 455 | static struct sk_usbhid * |
266 | if (devlist != NULL) | 456 | sk_probe(const char *application, const uint8_t *key_handle, |
267 | fido_dev_info_free(&devlist, MAX_FIDO_DEVICES); | 457 | size_t key_handle_len) |
458 | { | ||
459 | struct sk_usbhid *sk; | ||
460 | fido_dev_info_t *devlist; | ||
461 | size_t ndevs; | ||
462 | int r; | ||
268 | 463 | ||
269 | return dev; | 464 | if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) { |
465 | skdebug(__func__, "fido_dev_info_new failed"); | ||
466 | return NULL; | ||
467 | } | ||
468 | if ((r = fido_dev_info_manifest(devlist, MAX_FIDO_DEVICES, | ||
469 | &ndevs)) != FIDO_OK) { | ||
470 | skdebug(__func__, "fido_dev_info_manifest failed: %s", | ||
471 | fido_strerr(r)); | ||
472 | fido_dev_info_free(&devlist, MAX_FIDO_DEVICES); | ||
473 | return NULL; | ||
474 | } | ||
475 | skdebug(__func__, "%zu device(s) detected", ndevs); | ||
476 | if (ndevs == 0) { | ||
477 | sk = NULL; | ||
478 | } else if (application != NULL && key_handle != NULL) { | ||
479 | skdebug(__func__, "selecting sk by cred"); | ||
480 | sk = sk_select_by_cred(devlist, ndevs, application, key_handle, | ||
481 | key_handle_len); | ||
482 | } else { | ||
483 | skdebug(__func__, "selecting sk by touch"); | ||
484 | sk = sk_select_by_touch(devlist, ndevs); | ||
485 | } | ||
486 | fido_dev_info_free(&devlist, MAX_FIDO_DEVICES); | ||
487 | return sk; | ||
270 | } | 488 | } |
271 | 489 | ||
272 | #ifdef WITH_OPENSSL | 490 | #ifdef WITH_OPENSSL |
@@ -449,29 +667,29 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, | |||
449 | struct sk_option **options, struct sk_enroll_response **enroll_response) | 667 | struct sk_option **options, struct sk_enroll_response **enroll_response) |
450 | { | 668 | { |
451 | fido_cred_t *cred = NULL; | 669 | fido_cred_t *cred = NULL; |
452 | fido_dev_t *dev = NULL; | ||
453 | const uint8_t *ptr; | 670 | const uint8_t *ptr; |
454 | uint8_t user_id[32]; | 671 | uint8_t user_id[32]; |
672 | struct sk_usbhid *sk = NULL; | ||
455 | struct sk_enroll_response *response = NULL; | 673 | struct sk_enroll_response *response = NULL; |
456 | size_t len; | 674 | size_t len; |
675 | int credprot; | ||
457 | int cose_alg; | 676 | int cose_alg; |
458 | int ret = SSH_SK_ERR_GENERAL; | 677 | int ret = SSH_SK_ERR_GENERAL; |
459 | int r; | 678 | int r; |
460 | char *device = NULL; | 679 | char *device = NULL; |
461 | 680 | ||
462 | #ifdef SK_DEBUG | 681 | fido_init(SSH_FIDO_INIT_ARG); |
463 | fido_init(FIDO_DEBUG); | 682 | |
464 | #endif | ||
465 | if (enroll_response == NULL) { | 683 | if (enroll_response == NULL) { |
466 | skdebug(__func__, "enroll_response == NULL"); | 684 | skdebug(__func__, "enroll_response == NULL"); |
467 | goto out; | 685 | goto out; |
468 | } | 686 | } |
687 | *enroll_response = NULL; | ||
469 | memset(user_id, 0, sizeof(user_id)); | 688 | memset(user_id, 0, sizeof(user_id)); |
470 | if (check_enroll_options(options, &device, | 689 | if (check_enroll_options(options, &device, user_id, |
471 | user_id, sizeof(user_id)) != 0) | 690 | sizeof(user_id)) != 0) |
472 | goto out; /* error already logged */ | 691 | goto out; /* error already logged */ |
473 | 692 | ||
474 | *enroll_response = NULL; | ||
475 | switch(alg) { | 693 | switch(alg) { |
476 | #ifdef WITH_OPENSSL | 694 | #ifdef WITH_OPENSSL |
477 | case SSH_SK_ECDSA: | 695 | case SSH_SK_ECDSA: |
@@ -485,12 +703,15 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, | |||
485 | skdebug(__func__, "unsupported key type %d", alg); | 703 | skdebug(__func__, "unsupported key type %d", alg); |
486 | goto out; | 704 | goto out; |
487 | } | 705 | } |
488 | if (device == NULL && (device = pick_first_device()) == NULL) { | 706 | if (device != NULL) |
489 | ret = SSH_SK_ERR_DEVICE_NOT_FOUND; | 707 | sk = sk_open(device); |
490 | skdebug(__func__, "pick_first_device failed"); | 708 | else |
709 | sk = sk_probe(NULL, NULL, 0); | ||
710 | if (sk == NULL) { | ||
711 | skdebug(__func__, "failed to find sk"); | ||
491 | goto out; | 712 | goto out; |
492 | } | 713 | } |
493 | skdebug(__func__, "using device %s", device); | 714 | skdebug(__func__, "using device %s", sk->path); |
494 | if ((cred = fido_cred_new()) == NULL) { | 715 | if ((cred = fido_cred_new()) == NULL) { |
495 | skdebug(__func__, "fido_cred_new failed"); | 716 | skdebug(__func__, "fido_cred_new failed"); |
496 | goto out; | 717 | goto out; |
@@ -519,15 +740,34 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, | |||
519 | skdebug(__func__, "fido_cred_set_rp: %s", fido_strerr(r)); | 740 | skdebug(__func__, "fido_cred_set_rp: %s", fido_strerr(r)); |
520 | goto out; | 741 | goto out; |
521 | } | 742 | } |
522 | if ((dev = fido_dev_new()) == NULL) { | 743 | if ((flags & (SSH_SK_RESIDENT_KEY|SSH_SK_USER_VERIFICATION_REQD)) != 0) { |
523 | skdebug(__func__, "fido_dev_new failed"); | 744 | #if !defined(HAVE_FIDO_DEV_SUPPORTS_CRED_PROT) || \ |
524 | goto out; | 745 | !defined(HAVE_FIDO_CRED_SET_PROT) |
525 | } | 746 | skdebug(__func__, "libfido2 version does not support a feature required for this operation. Please upgrade to >=1.5.0"); |
526 | if ((r = fido_dev_open(dev, device)) != FIDO_OK) { | 747 | ret = SSH_SK_ERR_UNSUPPORTED; |
527 | skdebug(__func__, "fido_dev_open: %s", fido_strerr(r)); | ||
528 | goto out; | 748 | goto out; |
749 | credprot = 0; (void)credprot; /* avoid warning */ | ||
750 | #endif | ||
751 | if (!fido_dev_supports_cred_prot(sk->dev)) { | ||
752 | skdebug(__func__, "%s does not support credprot, " | ||
753 | "refusing to create unprotected " | ||
754 | "resident/verify-required key", sk->path); | ||
755 | ret = SSH_SK_ERR_UNSUPPORTED; | ||
756 | goto out; | ||
757 | } | ||
758 | if ((flags & SSH_SK_USER_VERIFICATION_REQD)) | ||
759 | credprot = FIDO_CRED_PROT_UV_REQUIRED; | ||
760 | else | ||
761 | credprot = FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID; | ||
762 | |||
763 | if ((r = fido_cred_set_prot(cred, credprot)) != FIDO_OK) { | ||
764 | skdebug(__func__, "fido_cred_set_prot: %s", | ||
765 | fido_strerr(r)); | ||
766 | ret = fidoerr_to_skerr(r); | ||
767 | goto out; | ||
768 | } | ||
529 | } | 769 | } |
530 | if ((r = fido_dev_make_cred(dev, cred, pin)) != FIDO_OK) { | 770 | if ((r = fido_dev_make_cred(sk->dev, cred, pin)) != FIDO_OK) { |
531 | skdebug(__func__, "fido_dev_make_cred: %s", fido_strerr(r)); | 771 | skdebug(__func__, "fido_dev_make_cred: %s", fido_strerr(r)); |
532 | ret = fidoerr_to_skerr(r); | 772 | ret = fidoerr_to_skerr(r); |
533 | goto out; | 773 | goto out; |
@@ -582,6 +822,16 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, | |||
582 | memcpy(response->attestation_cert, ptr, len); | 822 | memcpy(response->attestation_cert, ptr, len); |
583 | response->attestation_cert_len = len; | 823 | response->attestation_cert_len = len; |
584 | } | 824 | } |
825 | if ((ptr = fido_cred_authdata_ptr(cred)) != NULL) { | ||
826 | len = fido_cred_authdata_len(cred); | ||
827 | debug3("%s: authdata len=%zu", __func__, len); | ||
828 | if ((response->authdata = calloc(1, len)) == NULL) { | ||
829 | skdebug(__func__, "calloc authdata failed"); | ||
830 | goto out; | ||
831 | } | ||
832 | memcpy(response->authdata, ptr, len); | ||
833 | response->authdata_len = len; | ||
834 | } | ||
585 | *enroll_response = response; | 835 | *enroll_response = response; |
586 | response = NULL; | 836 | response = NULL; |
587 | ret = 0; | 837 | ret = 0; |
@@ -592,15 +842,11 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, | |||
592 | free(response->key_handle); | 842 | free(response->key_handle); |
593 | free(response->signature); | 843 | free(response->signature); |
594 | free(response->attestation_cert); | 844 | free(response->attestation_cert); |
845 | free(response->authdata); | ||
595 | free(response); | 846 | free(response); |
596 | } | 847 | } |
597 | if (dev != NULL) { | 848 | sk_close(sk); |
598 | fido_dev_close(dev); | 849 | fido_cred_free(&cred); |
599 | fido_dev_free(&dev); | ||
600 | } | ||
601 | if (cred != NULL) { | ||
602 | fido_cred_free(&cred); | ||
603 | } | ||
604 | return ret; | 850 | return ret; |
605 | } | 851 | } |
606 | 852 | ||
@@ -714,26 +960,6 @@ check_sign_load_resident_options(struct sk_option **options, char **devicep) | |||
714 | return 0; | 960 | return 0; |
715 | } | 961 | } |
716 | 962 | ||
717 | /* Calculate SHA256(m) */ | ||
718 | static int | ||
719 | sha256_mem(const void *m, size_t mlen, u_char *d, size_t dlen) | ||
720 | { | ||
721 | #ifdef WITH_OPENSSL | ||
722 | u_int mdlen; | ||
723 | #endif | ||
724 | |||
725 | if (dlen != 32) | ||
726 | return -1; | ||
727 | #ifdef WITH_OPENSSL | ||
728 | mdlen = dlen; | ||
729 | if (!EVP_Digest(m, mlen, d, &mdlen, EVP_sha256(), NULL)) | ||
730 | return -1; | ||
731 | #else | ||
732 | SHA256Data(m, mlen, d); | ||
733 | #endif | ||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | int | 963 | int |
738 | sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, | 964 | sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, |
739 | const char *application, | 965 | const char *application, |
@@ -743,15 +969,13 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, | |||
743 | { | 969 | { |
744 | fido_assert_t *assert = NULL; | 970 | fido_assert_t *assert = NULL; |
745 | char *device = NULL; | 971 | char *device = NULL; |
746 | fido_dev_t *dev = NULL; | 972 | struct sk_usbhid *sk = NULL; |
747 | struct sk_sign_response *response = NULL; | 973 | struct sk_sign_response *response = NULL; |
748 | uint8_t message[32]; | 974 | uint8_t message[32]; |
749 | int ret = SSH_SK_ERR_GENERAL; | 975 | int ret = SSH_SK_ERR_GENERAL; |
750 | int r; | 976 | int r; |
751 | 977 | ||
752 | #ifdef SK_DEBUG | 978 | fido_init(SSH_FIDO_INIT_ARG); |
753 | fido_init(FIDO_DEBUG); | ||
754 | #endif | ||
755 | 979 | ||
756 | if (sign_response == NULL) { | 980 | if (sign_response == NULL) { |
757 | skdebug(__func__, "sign_response == NULL"); | 981 | skdebug(__func__, "sign_response == NULL"); |
@@ -765,9 +989,14 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, | |||
765 | skdebug(__func__, "hash message failed"); | 989 | skdebug(__func__, "hash message failed"); |
766 | goto out; | 990 | goto out; |
767 | } | 991 | } |
768 | if ((dev = find_device(device, message, sizeof(message), | 992 | if (device != NULL) |
769 | application, key_handle, key_handle_len)) == NULL) { | 993 | sk = sk_open(device); |
770 | skdebug(__func__, "couldn't find device for key handle"); | 994 | else if (pin != NULL || (flags & SSH_SK_USER_VERIFICATION_REQD)) |
995 | sk = sk_probe(NULL, NULL, 0); | ||
996 | else | ||
997 | sk = sk_probe(application, key_handle, key_handle_len); | ||
998 | if (sk == NULL) { | ||
999 | skdebug(__func__, "failed to find sk"); | ||
771 | goto out; | 1000 | goto out; |
772 | } | 1001 | } |
773 | if ((assert = fido_assert_new()) == NULL) { | 1002 | if ((assert = fido_assert_new()) == NULL) { |
@@ -795,8 +1024,15 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, | |||
795 | skdebug(__func__, "fido_assert_set_up: %s", fido_strerr(r)); | 1024 | skdebug(__func__, "fido_assert_set_up: %s", fido_strerr(r)); |
796 | goto out; | 1025 | goto out; |
797 | } | 1026 | } |
798 | if ((r = fido_dev_get_assert(dev, assert, NULL)) != FIDO_OK) { | 1027 | if (pin == NULL && (flags & SSH_SK_USER_VERIFICATION_REQD) && |
1028 | (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) { | ||
1029 | skdebug(__func__, "fido_assert_set_uv: %s", fido_strerr(r)); | ||
1030 | ret = FIDO_ERR_PIN_REQUIRED; | ||
1031 | goto out; | ||
1032 | } | ||
1033 | if ((r = fido_dev_get_assert(sk->dev, assert, pin)) != FIDO_OK) { | ||
799 | skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r)); | 1034 | skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r)); |
1035 | ret = fidoerr_to_skerr(r); | ||
800 | goto out; | 1036 | goto out; |
801 | } | 1037 | } |
802 | if ((response = calloc(1, sizeof(*response))) == NULL) { | 1038 | if ((response = calloc(1, sizeof(*response))) == NULL) { |
@@ -820,22 +1056,16 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, | |||
820 | free(response->sig_s); | 1056 | free(response->sig_s); |
821 | free(response); | 1057 | free(response); |
822 | } | 1058 | } |
823 | if (dev != NULL) { | 1059 | sk_close(sk); |
824 | fido_dev_close(dev); | 1060 | fido_assert_free(&assert); |
825 | fido_dev_free(&dev); | ||
826 | } | ||
827 | if (assert != NULL) { | ||
828 | fido_assert_free(&assert); | ||
829 | } | ||
830 | return ret; | 1061 | return ret; |
831 | } | 1062 | } |
832 | 1063 | ||
833 | static int | 1064 | static int |
834 | read_rks(const char *devpath, const char *pin, | 1065 | read_rks(struct sk_usbhid *sk, const char *pin, |
835 | struct sk_resident_key ***rksp, size_t *nrksp) | 1066 | struct sk_resident_key ***rksp, size_t *nrksp) |
836 | { | 1067 | { |
837 | int ret = SSH_SK_ERR_GENERAL, r = -1; | 1068 | int ret = SSH_SK_ERR_GENERAL, r = -1; |
838 | fido_dev_t *dev = NULL; | ||
839 | fido_credman_metadata_t *metadata = NULL; | 1069 | fido_credman_metadata_t *metadata = NULL; |
840 | fido_credman_rp_t *rp = NULL; | 1070 | fido_credman_rp_t *rp = NULL; |
841 | fido_credman_rk_t *rk = NULL; | 1071 | fido_credman_rk_t *rk = NULL; |
@@ -843,30 +1073,25 @@ read_rks(const char *devpath, const char *pin, | |||
843 | const fido_cred_t *cred; | 1073 | const fido_cred_t *cred; |
844 | struct sk_resident_key *srk = NULL, **tmp; | 1074 | struct sk_resident_key *srk = NULL, **tmp; |
845 | 1075 | ||
846 | if ((dev = fido_dev_new()) == NULL) { | 1076 | if (pin == NULL) { |
847 | skdebug(__func__, "fido_dev_new failed"); | 1077 | skdebug(__func__, "no PIN specified"); |
848 | return ret; | 1078 | ret = SSH_SK_ERR_PIN_REQUIRED; |
849 | } | 1079 | goto out; |
850 | if ((r = fido_dev_open(dev, devpath)) != FIDO_OK) { | ||
851 | skdebug(__func__, "fido_dev_open %s failed: %s", | ||
852 | devpath, fido_strerr(r)); | ||
853 | fido_dev_free(&dev); | ||
854 | return ret; | ||
855 | } | 1080 | } |
856 | if ((metadata = fido_credman_metadata_new()) == NULL) { | 1081 | if ((metadata = fido_credman_metadata_new()) == NULL) { |
857 | skdebug(__func__, "alloc failed"); | 1082 | skdebug(__func__, "alloc failed"); |
858 | goto out; | 1083 | goto out; |
859 | } | 1084 | } |
860 | 1085 | ||
861 | if ((r = fido_credman_get_dev_metadata(dev, metadata, pin)) != 0) { | 1086 | if ((r = fido_credman_get_dev_metadata(sk->dev, metadata, pin)) != 0) { |
862 | if (r == FIDO_ERR_INVALID_COMMAND) { | 1087 | if (r == FIDO_ERR_INVALID_COMMAND) { |
863 | skdebug(__func__, "device %s does not support " | 1088 | skdebug(__func__, "device %s does not support " |
864 | "resident keys", devpath); | 1089 | "resident keys", sk->path); |
865 | ret = 0; | 1090 | ret = 0; |
866 | goto out; | 1091 | goto out; |
867 | } | 1092 | } |
868 | skdebug(__func__, "get metadata for %s failed: %s", | 1093 | skdebug(__func__, "get metadata for %s failed: %s", |
869 | devpath, fido_strerr(r)); | 1094 | sk->path, fido_strerr(r)); |
870 | ret = fidoerr_to_skerr(r); | 1095 | ret = fidoerr_to_skerr(r); |
871 | goto out; | 1096 | goto out; |
872 | } | 1097 | } |
@@ -877,14 +1102,14 @@ read_rks(const char *devpath, const char *pin, | |||
877 | skdebug(__func__, "alloc rp failed"); | 1102 | skdebug(__func__, "alloc rp failed"); |
878 | goto out; | 1103 | goto out; |
879 | } | 1104 | } |
880 | if ((r = fido_credman_get_dev_rp(dev, rp, pin)) != 0) { | 1105 | if ((r = fido_credman_get_dev_rp(sk->dev, rp, pin)) != 0) { |
881 | skdebug(__func__, "get RPs for %s failed: %s", | 1106 | skdebug(__func__, "get RPs for %s failed: %s", |
882 | devpath, fido_strerr(r)); | 1107 | sk->path, fido_strerr(r)); |
883 | goto out; | 1108 | goto out; |
884 | } | 1109 | } |
885 | nrp = fido_credman_rp_count(rp); | 1110 | nrp = fido_credman_rp_count(rp); |
886 | skdebug(__func__, "Device %s has resident keys for %zu RPs", | 1111 | skdebug(__func__, "Device %s has resident keys for %zu RPs", |
887 | devpath, nrp); | 1112 | sk->path, nrp); |
888 | 1113 | ||
889 | /* Iterate over RP IDs that have resident keys */ | 1114 | /* Iterate over RP IDs that have resident keys */ |
890 | for (i = 0; i < nrp; i++) { | 1115 | for (i = 0; i < nrp; i++) { |
@@ -901,10 +1126,10 @@ read_rks(const char *devpath, const char *pin, | |||
901 | skdebug(__func__, "alloc rk failed"); | 1126 | skdebug(__func__, "alloc rk failed"); |
902 | goto out; | 1127 | goto out; |
903 | } | 1128 | } |
904 | if ((r = fido_credman_get_dev_rk(dev, fido_credman_rp_id(rp, i), | 1129 | if ((r = fido_credman_get_dev_rk(sk->dev, |
905 | rk, pin)) != 0) { | 1130 | fido_credman_rp_id(rp, i), rk, pin)) != 0) { |
906 | skdebug(__func__, "get RKs for %s slot %zu failed: %s", | 1131 | skdebug(__func__, "get RKs for %s slot %zu failed: %s", |
907 | devpath, i, fido_strerr(r)); | 1132 | sk->path, i, fido_strerr(r)); |
908 | goto out; | 1133 | goto out; |
909 | } | 1134 | } |
910 | nrk = fido_credman_rk_count(rk); | 1135 | nrk = fido_credman_rk_count(rk); |
@@ -918,8 +1143,9 @@ read_rks(const char *devpath, const char *pin, | |||
918 | continue; | 1143 | continue; |
919 | } | 1144 | } |
920 | skdebug(__func__, "Device %s RP \"%s\" slot %zu: " | 1145 | skdebug(__func__, "Device %s RP \"%s\" slot %zu: " |
921 | "type %d", devpath, fido_credman_rp_id(rp, i), j, | 1146 | "type %d flags 0x%02x prot 0x%02x", sk->path, |
922 | fido_cred_type(cred)); | 1147 | fido_credman_rp_id(rp, i), j, fido_cred_type(cred), |
1148 | fido_cred_flags(cred), fido_cred_prot(cred)); | ||
923 | 1149 | ||
924 | /* build response entry */ | 1150 | /* build response entry */ |
925 | if ((srk = calloc(1, sizeof(*srk))) == NULL || | 1151 | if ((srk = calloc(1, sizeof(*srk))) == NULL || |
@@ -932,8 +1158,7 @@ read_rks(const char *devpath, const char *pin, | |||
932 | } | 1158 | } |
933 | 1159 | ||
934 | srk->key.key_handle_len = fido_cred_id_len(cred); | 1160 | srk->key.key_handle_len = fido_cred_id_len(cred); |
935 | memcpy(srk->key.key_handle, | 1161 | memcpy(srk->key.key_handle, fido_cred_id_ptr(cred), |
936 | fido_cred_id_ptr(cred), | ||
937 | srk->key.key_handle_len); | 1162 | srk->key.key_handle_len); |
938 | 1163 | ||
939 | switch (fido_cred_type(cred)) { | 1164 | switch (fido_cred_type(cred)) { |
@@ -949,6 +1174,9 @@ read_rks(const char *devpath, const char *pin, | |||
949 | goto out; /* XXX free rk and continue */ | 1174 | goto out; /* XXX free rk and continue */ |
950 | } | 1175 | } |
951 | 1176 | ||
1177 | if (fido_cred_prot(cred) == FIDO_CRED_PROT_UV_REQUIRED) | ||
1178 | srk->flags |= SSH_SK_USER_VERIFICATION_REQD; | ||
1179 | |||
952 | if ((r = pack_public_key(srk->alg, cred, | 1180 | if ((r = pack_public_key(srk->alg, cred, |
953 | &srk->key)) != 0) { | 1181 | &srk->key)) != 0) { |
954 | skdebug(__func__, "pack public key failed"); | 1182 | skdebug(__func__, "pack public key failed"); |
@@ -976,8 +1204,6 @@ read_rks(const char *devpath, const char *pin, | |||
976 | } | 1204 | } |
977 | fido_credman_rp_free(&rp); | 1205 | fido_credman_rp_free(&rp); |
978 | fido_credman_rk_free(&rk); | 1206 | fido_credman_rk_free(&rk); |
979 | fido_dev_close(dev); | ||
980 | fido_dev_free(&dev); | ||
981 | fido_credman_metadata_free(&metadata); | 1207 | fido_credman_metadata_free(&metadata); |
982 | return ret; | 1208 | return ret; |
983 | } | 1209 | } |
@@ -987,50 +1213,31 @@ sk_load_resident_keys(const char *pin, struct sk_option **options, | |||
987 | struct sk_resident_key ***rksp, size_t *nrksp) | 1213 | struct sk_resident_key ***rksp, size_t *nrksp) |
988 | { | 1214 | { |
989 | int ret = SSH_SK_ERR_GENERAL, r = -1; | 1215 | int ret = SSH_SK_ERR_GENERAL, r = -1; |
990 | fido_dev_info_t *devlist = NULL; | 1216 | size_t i, nrks = 0; |
991 | size_t i, ndev = 0, nrks = 0; | ||
992 | const fido_dev_info_t *di; | ||
993 | struct sk_resident_key **rks = NULL; | 1217 | struct sk_resident_key **rks = NULL; |
1218 | struct sk_usbhid *sk = NULL; | ||
994 | char *device = NULL; | 1219 | char *device = NULL; |
1220 | |||
995 | *rksp = NULL; | 1221 | *rksp = NULL; |
996 | *nrksp = 0; | 1222 | *nrksp = 0; |
997 | 1223 | ||
1224 | fido_init(SSH_FIDO_INIT_ARG); | ||
1225 | |||
998 | if (check_sign_load_resident_options(options, &device) != 0) | 1226 | if (check_sign_load_resident_options(options, &device) != 0) |
999 | goto out; /* error already logged */ | 1227 | goto out; /* error already logged */ |
1000 | if (device != NULL) { | 1228 | if (device != NULL) |
1001 | skdebug(__func__, "trying %s", device); | 1229 | sk = sk_open(device); |
1002 | if ((r = read_rks(device, pin, &rks, &nrks)) != 0) { | 1230 | else |
1003 | skdebug(__func__, "read_rks failed for %s", device); | 1231 | sk = sk_probe(NULL, NULL, 0); |
1004 | ret = r; | 1232 | if (sk == NULL) { |
1005 | goto out; | 1233 | skdebug(__func__, "failed to find sk"); |
1006 | } | 1234 | goto out; |
1007 | } else { | 1235 | } |
1008 | /* Try all devices */ | 1236 | skdebug(__func__, "trying %s", sk->path); |
1009 | if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) { | 1237 | if ((r = read_rks(sk, pin, &rks, &nrks)) != 0) { |
1010 | skdebug(__func__, "fido_dev_info_new failed"); | 1238 | skdebug(__func__, "read_rks failed for %s", sk->path); |
1011 | goto out; | 1239 | ret = r; |
1012 | } | 1240 | goto out; |
1013 | if ((r = fido_dev_info_manifest(devlist, | ||
1014 | MAX_FIDO_DEVICES, &ndev)) != FIDO_OK) { | ||
1015 | skdebug(__func__, "fido_dev_info_manifest failed: %s", | ||
1016 | fido_strerr(r)); | ||
1017 | goto out; | ||
1018 | } | ||
1019 | for (i = 0; i < ndev; i++) { | ||
1020 | if ((di = fido_dev_info_ptr(devlist, i)) == NULL) { | ||
1021 | skdebug(__func__, "no dev info at %zu", i); | ||
1022 | continue; | ||
1023 | } | ||
1024 | skdebug(__func__, "trying %s", fido_dev_info_path(di)); | ||
1025 | if ((r = read_rks(fido_dev_info_path(di), pin, | ||
1026 | &rks, &nrks)) != 0) { | ||
1027 | skdebug(__func__, "read_rks failed for %s", | ||
1028 | fido_dev_info_path(di)); | ||
1029 | /* remember last error */ | ||
1030 | ret = r; | ||
1031 | continue; | ||
1032 | } | ||
1033 | } | ||
1034 | } | 1241 | } |
1035 | /* success, unless we have no keys but a specific error */ | 1242 | /* success, unless we have no keys but a specific error */ |
1036 | if (nrks > 0 || ret == SSH_SK_ERR_GENERAL) | 1243 | if (nrks > 0 || ret == SSH_SK_ERR_GENERAL) |
@@ -1040,7 +1247,7 @@ sk_load_resident_keys(const char *pin, struct sk_option **options, | |||
1040 | rks = NULL; | 1247 | rks = NULL; |
1041 | nrks = 0; | 1248 | nrks = 0; |
1042 | out: | 1249 | out: |
1043 | free(device); | 1250 | sk_close(sk); |
1044 | for (i = 0; i < nrks; i++) { | 1251 | for (i = 0; i < nrks; i++) { |
1045 | free(rks[i]->application); | 1252 | free(rks[i]->application); |
1046 | freezero(rks[i]->key.public_key, rks[i]->key.public_key_len); | 1253 | freezero(rks[i]->key.public_key, rks[i]->key.public_key_len); |
@@ -1048,7 +1255,6 @@ sk_load_resident_keys(const char *pin, struct sk_option **options, | |||
1048 | freezero(rks[i], sizeof(*rks[i])); | 1255 | freezero(rks[i], sizeof(*rks[i])); |
1049 | } | 1256 | } |
1050 | free(rks); | 1257 | free(rks); |
1051 | fido_dev_info_free(&devlist, MAX_FIDO_DEVICES); | ||
1052 | return ret; | 1258 | return ret; |
1053 | } | 1259 | } |
1054 | 1260 | ||