summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sk-usbhid.c578
-rw-r--r--ssh-keygen.c7
2 files changed, 332 insertions, 253 deletions
diff --git a/sk-usbhid.c b/sk-usbhid.c
index 1dd834883..2efb377c5 100644
--- a/sk-usbhid.c
+++ b/sk-usbhid.c
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (c) 2019 Markus Friedl 2 * Copyright (c) 2019 Markus Friedl
3 * Copyright (c) 2020 Pedro Martelletto
3 * 4 *
4 * Permission to use, copy, modify, and distribute this software for any 5 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above 6 * purpose with or without fee is hereby granted, provided that the above
@@ -43,6 +44,7 @@
43#ifndef SK_STANDALONE 44#ifndef SK_STANDALONE
44# include "log.h" 45# include "log.h"
45# include "xmalloc.h" 46# include "xmalloc.h"
47# include "misc.h"
46/* 48/*
47 * If building as part of OpenSSH, then rename exported functions. 49 * If building as part of OpenSSH, then rename exported functions.
48 * This must be done before including sk-api.h. 50 * This must be done before including sk-api.h.
@@ -63,7 +65,10 @@
63#define SSH_FIDO_INIT_ARG 0 65#define SSH_FIDO_INIT_ARG 0
64#endif 66#endif
65 67
66#define MAX_FIDO_DEVICES 256 68#define MAX_FIDO_DEVICES 8
69#define FIDO_POLL_MS 50
70#define SELECT_MS 15000
71#define POLL_SLEEP_NS 200000000
67 72
68/* Compatibility with OpenSSH 1.0.x */ 73/* Compatibility with OpenSSH 1.0.x */
69#if (OPENSSL_VERSION_NUMBER < 0x10100000L) 74#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
@@ -74,6 +79,11 @@
74 } while (0) 79 } while (0)
75#endif 80#endif
76 81
82struct sk_usbhid {
83 fido_dev_t *dev;
84 char *path;
85};
86
77/* Return the version of the middleware API */ 87/* Return the version of the middleware API */
78uint32_t sk_api_version(void); 88uint32_t sk_api_version(void);
79 89
@@ -127,54 +137,185 @@ sk_api_version(void)
127 return SSH_SK_VERSION_MAJOR; 137 return SSH_SK_VERSION_MAJOR;
128} 138}
129 139
130/* Select the first identified FIDO device attached to the system */ 140static struct sk_usbhid *
131static char * 141sk_open(const char *path)
132pick_first_device(void)
133{ 142{
134 char *ret = NULL; 143 struct sk_usbhid *sk;
135 fido_dev_info_t *devlist = NULL;
136 size_t olen = 0;
137 int r; 144 int r;
138 const fido_dev_info_t *di;
139 145
140 if ((devlist = fido_dev_info_new(1)) == NULL) { 146 if (path == NULL) {
141 skdebug(__func__, "fido_dev_info_new failed"); 147 skdebug(__func__, "path == NULL");
142 goto out; 148 return NULL;
143 } 149 }
144 if ((r = fido_dev_info_manifest(devlist, 1, &olen)) != FIDO_OK) { 150 if ((sk = calloc(1, sizeof(*sk))) == NULL) {
145 skdebug(__func__, "fido_dev_info_manifest failed: %s", 151 skdebug(__func__, "calloc sk failed");
152 return NULL;
153 }
154 if ((sk->path = strdup(path)) == NULL) {
155 skdebug(__func__, "strdup path failed");
156 free(sk);
157 return NULL;
158 }
159 if ((sk->dev = fido_dev_new()) == NULL) {
160 skdebug(__func__, "fido_dev_new failed");
161 free(sk->path);
162 free(sk);
163 return NULL;
164 }
165 if ((r = fido_dev_open(sk->dev, sk->path)) != FIDO_OK) {
166 skdebug(__func__, "fido_dev_open %s failed: %s", sk->path,
146 fido_strerr(r)); 167 fido_strerr(r));
147 goto out; 168 fido_dev_free(&sk->dev);
169 free(sk->path);
170 free(sk);
171 return NULL;
148 } 172 }
149 if (olen != 1) { 173 return sk;
150 skdebug(__func__, "fido_dev_info_manifest bad len %zu", olen); 174}
151 goto out; 175
176static void
177sk_close(struct sk_usbhid *sk)
178{
179 if (sk == NULL)
180 return;
181 fido_dev_cancel(sk->dev); /* cancel any pending operation */
182 fido_dev_close(sk->dev);
183 fido_dev_free(&sk->dev);
184 free(sk->path);
185 free(sk);
186}
187
188static struct sk_usbhid **
189sk_openv(const fido_dev_info_t *devlist, size_t ndevs, size_t *nopen)
190{
191 const fido_dev_info_t *di;
192 struct sk_usbhid **skv;
193 size_t i;
194
195 *nopen = 0;
196 if ((skv = calloc(ndevs, sizeof(*skv))) == NULL) {
197 skdebug(__func__, "calloc skv failed");
198 return NULL;
152 } 199 }
153 di = fido_dev_info_ptr(devlist, 0); 200 for (i = 0; i < ndevs; i++) {
154 if ((ret = strdup(fido_dev_info_path(di))) == NULL) { 201 if ((di = fido_dev_info_ptr(devlist, i)) == NULL)
155 skdebug(__func__, "fido_dev_info_path failed"); 202 skdebug(__func__, "fido_dev_info_ptr failed");
156 goto out; 203 else if ((skv[*nopen] = sk_open(fido_dev_info_path(di))) == NULL)
204 skdebug(__func__, "sk_open failed");
205 else
206 (*nopen)++;
157 } 207 }
158 out: 208 if (*nopen == 0) {
159 fido_dev_info_free(&devlist, 1); 209 for (i = 0; i < ndevs; i++)
160 return ret; 210 sk_close(skv[i]);
211 free(skv);
212 skv = NULL;
213 }
214
215 return skv;
216}
217
218static void
219sk_closev(struct sk_usbhid **skv, size_t nsk)
220{
221 size_t i;
222
223 for (i = 0; i < nsk; i++)
224 sk_close(skv[i]);
225 free(skv);
161} 226}
162 227
163/* Check if the specified key handle exists on a given device. */
164static int 228static int
165try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len, 229sk_touch_begin(struct sk_usbhid **skv, size_t nsk)
166 const char *application, const uint8_t *key_handle, size_t key_handle_len, 230{
167 uint8_t flags, const char *pin) 231 size_t i, ok = 0;
232 int r;
233
234 for (i = 0; i < nsk; i++)
235 if ((r = fido_dev_get_touch_begin(skv[i]->dev)) != FIDO_OK)
236 skdebug(__func__, "fido_dev_get_touch_begin %s failed:"
237 " %s", skv[i]->path, fido_strerr(r));
238 else
239 ok++;
240
241 return ok ? 0 : -1;
242}
243
244static int
245sk_touch_poll(struct sk_usbhid **skv, size_t nsk, int *touch, size_t *idx)
246{
247 struct timespec ts_pause;
248 size_t npoll, i;
249 int r;
250
251 ts_pause.tv_sec = 0;
252 ts_pause.tv_nsec = POLL_SLEEP_NS;
253 nanosleep(&ts_pause, NULL);
254 npoll = nsk;
255 for (i = 0; i < nsk; i++) {
256 if (skv[i] == NULL)
257 continue; /* device discarded */
258 skdebug(__func__, "polling %s", skv[i]->path);
259 if ((r = fido_dev_get_touch_status(skv[i]->dev, touch,
260 FIDO_POLL_MS)) != FIDO_OK) {
261 skdebug(__func__, "fido_dev_get_touch_status %s: %s",
262 skv[i]->path, fido_strerr(r));
263 sk_close(skv[i]); /* discard device */
264 skv[i] = NULL;
265 if (--npoll == 0) {
266 skdebug(__func__, "no device left to poll");
267 return -1;
268 }
269 } else if (*touch) {
270 *idx = i;
271 return 0;
272 }
273 }
274 *touch = 0;
275 return 0;
276}
277
278/* Calculate SHA256(m) */
279static int
280sha256_mem(const void *m, size_t mlen, u_char *d, size_t dlen)
281{
282#ifdef WITH_OPENSSL
283 u_int mdlen;
284#endif
285
286 if (dlen != 32)
287 return -1;
288#ifdef WITH_OPENSSL
289 mdlen = dlen;
290 if (!EVP_Digest(m, mlen, d, &mdlen, EVP_sha256(), NULL))
291 return -1;
292#else
293 SHA256Data(m, mlen, d);
294#endif
295 return 0;
296}
297
298/* Check if the specified key handle exists on a given sk. */
299static int
300sk_try(const struct sk_usbhid *sk, const char *application,
301 const uint8_t *key_handle, size_t key_handle_len)
168{ 302{
169 fido_assert_t *assert = NULL; 303 fido_assert_t *assert = NULL;
304 /* generate an invalid signature on FIDO2 tokens */
305 const char *data = "";
306 uint8_t message[32];
170 int r = FIDO_ERR_INTERNAL; 307 int r = FIDO_ERR_INTERNAL;
171 308
309 if (sha256_mem(data, strlen(data), message, sizeof(message)) != 0) {
310 skdebug(__func__, "hash message failed");
311 goto out;
312 }
172 if ((assert = fido_assert_new()) == NULL) { 313 if ((assert = fido_assert_new()) == NULL) {
173 skdebug(__func__, "fido_assert_new failed"); 314 skdebug(__func__, "fido_assert_new failed");
174 goto out; 315 goto out;
175 } 316 }
176 if ((r = fido_assert_set_clientdata_hash(assert, message, 317 if ((r = fido_assert_set_clientdata_hash(assert, message,
177 message_len)) != FIDO_OK) { 318 sizeof(message))) != FIDO_OK) {
178 skdebug(__func__, "fido_assert_set_clientdata_hash: %s", 319 skdebug(__func__, "fido_assert_set_clientdata_hash: %s",
179 fido_strerr(r)); 320 fido_strerr(r));
180 goto out; 321 goto out;
@@ -192,7 +333,7 @@ try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len,
192 skdebug(__func__, "fido_assert_up: %s", fido_strerr(r)); 333 skdebug(__func__, "fido_assert_up: %s", fido_strerr(r));
193 goto out; 334 goto out;
194 } 335 }
195 r = fido_dev_get_assert(dev, assert, pin); 336 r = fido_dev_get_assert(sk->dev, assert, NULL);
196 skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r)); 337 skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
197 if (r == FIDO_ERR_USER_PRESENCE_REQUIRED) { 338 if (r == FIDO_ERR_USER_PRESENCE_REQUIRED) {
198 /* U2F tokens may return this */ 339 /* U2F tokens may return this */
@@ -204,77 +345,110 @@ try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len,
204 return r != FIDO_OK ? -1 : 0; 345 return r != FIDO_OK ? -1 : 0;
205} 346}
206 347
207/* Iterate over configured devices looking for a specific key handle */ 348static struct sk_usbhid *
208static fido_dev_t * 349sk_select_by_cred(const fido_dev_info_t *devlist, size_t ndevs,
209find_device(const char *path, const uint8_t *message, size_t message_len, 350 const char *application, const uint8_t *key_handle, size_t key_handle_len)
210 const char *application, const uint8_t *key_handle, size_t key_handle_len,
211 uint8_t flags, const char *pin)
212{ 351{
213 fido_dev_info_t *devlist = NULL; 352 struct sk_usbhid **skv, *sk;
214 fido_dev_t *dev = NULL; 353 size_t skvcnt, i;
215 size_t devlist_len = 0, i; 354
216 int r; 355 if ((skv = sk_openv(devlist, ndevs, &skvcnt)) == NULL) {
217 356 skdebug(__func__, "sk_openv failed");
218 if (path != NULL) { 357 return NULL;
219 if ((dev = fido_dev_new()) == NULL) { 358 }
220 skdebug(__func__, "fido_dev_new failed"); 359 sk = NULL;
221 return NULL; 360 for (i = 0; i < skvcnt; i++)
222 } 361 if (sk_try(skv[i], application, key_handle,
223 if ((r = fido_dev_open(dev, path)) != FIDO_OK) { 362 key_handle_len) == 0) {
224 skdebug(__func__, "fido_dev_open failed"); 363 sk = skv[i];
225 fido_dev_free(&dev); 364 skv[i] = NULL;
226 return NULL; 365 skdebug(__func__, "found key in %s", sk->path);
366 break;
227 } 367 }
228 return dev; 368 sk_closev(skv, skvcnt);
229 } 369 return sk;
370}
230 371
231 if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) { 372static struct sk_usbhid *
232 skdebug(__func__, "fido_dev_info_new failed"); 373sk_select_by_touch(const fido_dev_info_t *devlist, size_t ndevs)
374{
375 struct sk_usbhid **skv, *sk;
376 struct timeval tv_start, tv_now, tv_delta;
377 size_t skvcnt, idx;
378 int touch, ms_remain;
379
380 if ((skv = sk_openv(devlist, ndevs, &skvcnt)) == NULL) {
381 skdebug(__func__, "sk_openv failed");
382 return NULL;
383 }
384 sk = NULL;
385 if (skvcnt < 2) {
386 if (skvcnt == 1) {
387 /* single candidate */
388 sk = skv[0];
389 skv[0] = NULL;
390 }
233 goto out; 391 goto out;
234 } 392 }
235 if ((r = fido_dev_info_manifest(devlist, MAX_FIDO_DEVICES, 393 if (sk_touch_begin(skv, skvcnt) == -1) {
236 &devlist_len)) != FIDO_OK) { 394 skdebug(__func__, "sk_touch_begin failed");
237 skdebug(__func__, "fido_dev_info_manifest: %s", fido_strerr(r));
238 goto out; 395 goto out;
239 } 396 }
240 397 monotime_tv(&tv_start);
241 skdebug(__func__, "found %zu device(s)", devlist_len); 398 do {
242 399 if (sk_touch_poll(skv, skvcnt, &touch, &idx) == -1) {
243 for (i = 0; i < devlist_len; i++) { 400 skdebug(__func__, "sk_touch_poll failed");
244 const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i); 401 goto out;
245
246 if (di == NULL) {
247 skdebug(__func__, "fido_dev_info_ptr %zu failed", i);
248 continue;
249 }
250 if ((path = fido_dev_info_path(di)) == NULL) {
251 skdebug(__func__, "fido_dev_info_path %zu failed", i);
252 continue;
253 }
254 skdebug(__func__, "trying device %zu: %s", i, path);
255 if ((dev = fido_dev_new()) == NULL) {
256 skdebug(__func__, "fido_dev_new failed");
257 continue;
258 }
259 if ((r = fido_dev_open(dev, path)) != FIDO_OK) {
260 skdebug(__func__, "fido_dev_open failed");
261 fido_dev_free(&dev);
262 continue;
263 } 402 }
264 if (try_device(dev, message, message_len, application, 403 if (touch) {
265 key_handle, key_handle_len, flags, pin) == 0) { 404 sk = skv[idx];
266 skdebug(__func__, "found key"); 405 skv[idx] = NULL;
267 break; 406 goto out;
268 } 407 }
269 fido_dev_close(dev); 408 monotime_tv(&tv_now);
270 fido_dev_free(&dev); 409 timersub(&tv_now, &tv_start, &tv_delta);
271 } 410 ms_remain = SELECT_MS - tv_delta.tv_sec * 1000 -
411 tv_delta.tv_usec / 1000;
412 } while (ms_remain >= FIDO_POLL_MS);
413 skdebug(__func__, "timeout");
414out:
415 sk_closev(skv, skvcnt);
416 return sk;
417}
272 418
273 out: 419static struct sk_usbhid *
274 if (devlist != NULL) 420sk_probe(const char *application, const uint8_t *key_handle,
275 fido_dev_info_free(&devlist, MAX_FIDO_DEVICES); 421 size_t key_handle_len)
422{
423 struct sk_usbhid *sk;
424 fido_dev_info_t *devlist;
425 size_t ndevs;
426 int r;
276 427
277 return dev; 428 if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) {
429 skdebug(__func__, "fido_dev_info_new failed");
430 return NULL;
431 }
432 if ((r = fido_dev_info_manifest(devlist, MAX_FIDO_DEVICES,
433 &ndevs)) != FIDO_OK) {
434 skdebug(__func__, "fido_dev_info_manifest failed: %s",
435 fido_strerr(r));
436 fido_dev_info_free(&devlist, MAX_FIDO_DEVICES);
437 return NULL;
438 }
439 skdebug(__func__, "%zu device(s) detected", ndevs);
440 if (ndevs == 0) {
441 sk = NULL;
442 } else if (application != NULL && key_handle != NULL) {
443 skdebug(__func__, "selecting sk by cred");
444 sk = sk_select_by_cred(devlist, ndevs, application, key_handle,
445 key_handle_len);
446 } else {
447 skdebug(__func__, "selecting sk by touch");
448 sk = sk_select_by_touch(devlist, ndevs);
449 }
450 fido_dev_info_free(&devlist, MAX_FIDO_DEVICES);
451 return sk;
278} 452}
279 453
280#ifdef WITH_OPENSSL 454#ifdef WITH_OPENSSL
@@ -451,52 +625,15 @@ check_enroll_options(struct sk_option **options, char **devicep,
451 return 0; 625 return 0;
452} 626}
453 627
454static int
455check_sk_extensions(fido_dev_t *dev, const char *ext, int *ret)
456{
457 fido_cbor_info_t *info;
458 char * const *ptr;
459 size_t len, i;
460 int r;
461
462 *ret = 0;
463
464 if (!fido_dev_is_fido2(dev)) {
465 skdebug(__func__, "device is not fido2");
466 return 0;
467 }
468 if ((info = fido_cbor_info_new()) == NULL) {
469 skdebug(__func__, "fido_cbor_info_new failed");
470 return -1;
471 }
472 if ((r = fido_dev_get_cbor_info(dev, info)) != FIDO_OK) {
473 skdebug(__func__, "fido_dev_get_cbor_info: %s", fido_strerr(r));
474 fido_cbor_info_free(&info);
475 return -1;
476 }
477 ptr = fido_cbor_info_extensions_ptr(info);
478 len = fido_cbor_info_extensions_len(info);
479 for (i = 0; i < len; i++) {
480 if (!strcmp(ptr[i], ext)) {
481 *ret = 1;
482 break;
483 }
484 }
485 fido_cbor_info_free(&info);
486 skdebug(__func__, "extension %s %s", ext, *ret ? "present" : "absent");
487
488 return 0;
489}
490
491int 628int
492sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, 629sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
493 const char *application, uint8_t flags, const char *pin, 630 const char *application, uint8_t flags, const char *pin,
494 struct sk_option **options, struct sk_enroll_response **enroll_response) 631 struct sk_option **options, struct sk_enroll_response **enroll_response)
495{ 632{
496 fido_cred_t *cred = NULL; 633 fido_cred_t *cred = NULL;
497 fido_dev_t *dev = NULL;
498 const uint8_t *ptr; 634 const uint8_t *ptr;
499 uint8_t user_id[32]; 635 uint8_t user_id[32];
636 struct sk_usbhid *sk = NULL;
500 struct sk_enroll_response *response = NULL; 637 struct sk_enroll_response *response = NULL;
501 size_t len; 638 size_t len;
502 int credprot; 639 int credprot;
@@ -511,12 +648,12 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
511 skdebug(__func__, "enroll_response == NULL"); 648 skdebug(__func__, "enroll_response == NULL");
512 goto out; 649 goto out;
513 } 650 }
651 *enroll_response = NULL;
514 memset(user_id, 0, sizeof(user_id)); 652 memset(user_id, 0, sizeof(user_id));
515 if (check_enroll_options(options, &device, 653 if (check_enroll_options(options, &device, user_id,
516 user_id, sizeof(user_id)) != 0) 654 sizeof(user_id)) != 0)
517 goto out; /* error already logged */ 655 goto out; /* error already logged */
518 656
519 *enroll_response = NULL;
520 switch(alg) { 657 switch(alg) {
521#ifdef WITH_OPENSSL 658#ifdef WITH_OPENSSL
522 case SSH_SK_ECDSA: 659 case SSH_SK_ECDSA:
@@ -530,12 +667,15 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
530 skdebug(__func__, "unsupported key type %d", alg); 667 skdebug(__func__, "unsupported key type %d", alg);
531 goto out; 668 goto out;
532 } 669 }
533 if (device == NULL && (device = pick_first_device()) == NULL) { 670 if (device != NULL)
534 ret = SSH_SK_ERR_DEVICE_NOT_FOUND; 671 sk = sk_open(device);
535 skdebug(__func__, "pick_first_device failed"); 672 else
673 sk = sk_probe(NULL, NULL, 0);
674 if (sk == NULL) {
675 skdebug(__func__, "failed to find sk");
536 goto out; 676 goto out;
537 } 677 }
538 skdebug(__func__, "using device %s", device); 678 skdebug(__func__, "using device %s", sk->path);
539 if ((cred = fido_cred_new()) == NULL) { 679 if ((cred = fido_cred_new()) == NULL) {
540 skdebug(__func__, "fido_cred_new failed"); 680 skdebug(__func__, "fido_cred_new failed");
541 goto out; 681 goto out;
@@ -564,22 +704,11 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
564 skdebug(__func__, "fido_cred_set_rp: %s", fido_strerr(r)); 704 skdebug(__func__, "fido_cred_set_rp: %s", fido_strerr(r));
565 goto out; 705 goto out;
566 } 706 }
567 if ((dev = fido_dev_new()) == NULL) {
568 skdebug(__func__, "fido_dev_new failed");
569 goto out;
570 }
571 if ((r = fido_dev_open(dev, device)) != FIDO_OK) {
572 skdebug(__func__, "fido_dev_open: %s", fido_strerr(r));
573 goto out;
574 }
575 if ((flags & (SSH_SK_RESIDENT_KEY|SSH_SK_USER_VERIFICATION_REQD)) != 0) { 707 if ((flags & (SSH_SK_RESIDENT_KEY|SSH_SK_USER_VERIFICATION_REQD)) != 0) {
576 if (check_sk_extensions(dev, "credProtect", &credprot) < 0) { 708 if (!fido_dev_supports_cred_prot(sk->dev)) {
577 skdebug(__func__, "check_sk_extensions failed"); 709 skdebug(__func__, "%s does not support credprot, "
578 goto out; 710 "refusing to create unprotected "
579 } 711 "resident/verify-required key", sk->path);
580 if (credprot == 0) {
581 skdebug(__func__, "refusing to create unprotected "
582 "resident/verify-required key");
583 ret = SSH_SK_ERR_UNSUPPORTED; 712 ret = SSH_SK_ERR_UNSUPPORTED;
584 goto out; 713 goto out;
585 } 714 }
@@ -595,7 +724,7 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
595 goto out; 724 goto out;
596 } 725 }
597 } 726 }
598 if ((r = fido_dev_make_cred(dev, cred, pin)) != FIDO_OK) { 727 if ((r = fido_dev_make_cred(sk->dev, cred, pin)) != FIDO_OK) {
599 skdebug(__func__, "fido_dev_make_cred: %s", fido_strerr(r)); 728 skdebug(__func__, "fido_dev_make_cred: %s", fido_strerr(r));
600 ret = fidoerr_to_skerr(r); 729 ret = fidoerr_to_skerr(r);
601 goto out; 730 goto out;
@@ -662,13 +791,8 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
662 free(response->attestation_cert); 791 free(response->attestation_cert);
663 free(response); 792 free(response);
664 } 793 }
665 if (dev != NULL) { 794 sk_close(sk);
666 fido_dev_close(dev); 795 fido_cred_free(&cred);
667 fido_dev_free(&dev);
668 }
669 if (cred != NULL) {
670 fido_cred_free(&cred);
671 }
672 return ret; 796 return ret;
673} 797}
674 798
@@ -782,26 +906,6 @@ check_sign_load_resident_options(struct sk_option **options, char **devicep)
782 return 0; 906 return 0;
783} 907}
784 908
785/* Calculate SHA256(m) */
786static int
787sha256_mem(const void *m, size_t mlen, u_char *d, size_t dlen)
788{
789#ifdef WITH_OPENSSL
790 u_int mdlen;
791#endif
792
793 if (dlen != 32)
794 return -1;
795#ifdef WITH_OPENSSL
796 mdlen = dlen;
797 if (!EVP_Digest(m, mlen, d, &mdlen, EVP_sha256(), NULL))
798 return -1;
799#else
800 SHA256Data(m, mlen, d);
801#endif
802 return 0;
803}
804
805int 909int
806sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, 910sk_sign(uint32_t alg, const uint8_t *data, size_t datalen,
807 const char *application, 911 const char *application,
@@ -811,7 +915,7 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen,
811{ 915{
812 fido_assert_t *assert = NULL; 916 fido_assert_t *assert = NULL;
813 char *device = NULL; 917 char *device = NULL;
814 fido_dev_t *dev = NULL; 918 struct sk_usbhid *sk = NULL;
815 struct sk_sign_response *response = NULL; 919 struct sk_sign_response *response = NULL;
816 uint8_t message[32]; 920 uint8_t message[32];
817 int ret = SSH_SK_ERR_GENERAL; 921 int ret = SSH_SK_ERR_GENERAL;
@@ -831,9 +935,14 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen,
831 skdebug(__func__, "hash message failed"); 935 skdebug(__func__, "hash message failed");
832 goto out; 936 goto out;
833 } 937 }
834 if ((dev = find_device(device, message, sizeof(message), 938 if (device != NULL)
835 application, key_handle, key_handle_len, flags, pin)) == NULL) { 939 sk = sk_open(device);
836 skdebug(__func__, "couldn't find device for key handle"); 940 else if (pin != NULL || (flags & SSH_SK_USER_VERIFICATION_REQD))
941 sk = sk_probe(NULL, NULL, 0);
942 else
943 sk = sk_probe(application, key_handle, key_handle_len);
944 if (sk == NULL) {
945 skdebug(__func__, "failed to find sk");
837 goto out; 946 goto out;
838 } 947 }
839 if ((assert = fido_assert_new()) == NULL) { 948 if ((assert = fido_assert_new()) == NULL) {
@@ -867,7 +976,7 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen,
867 ret = FIDO_ERR_PIN_REQUIRED; 976 ret = FIDO_ERR_PIN_REQUIRED;
868 goto out; 977 goto out;
869 } 978 }
870 if ((r = fido_dev_get_assert(dev, assert, pin)) != FIDO_OK) { 979 if ((r = fido_dev_get_assert(sk->dev, assert, pin)) != FIDO_OK) {
871 skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r)); 980 skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
872 ret = fidoerr_to_skerr(r); 981 ret = fidoerr_to_skerr(r);
873 goto out; 982 goto out;
@@ -893,22 +1002,16 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen,
893 free(response->sig_s); 1002 free(response->sig_s);
894 free(response); 1003 free(response);
895 } 1004 }
896 if (dev != NULL) { 1005 sk_close(sk);
897 fido_dev_close(dev); 1006 fido_assert_free(&assert);
898 fido_dev_free(&dev);
899 }
900 if (assert != NULL) {
901 fido_assert_free(&assert);
902 }
903 return ret; 1007 return ret;
904} 1008}
905 1009
906static int 1010static int
907read_rks(const char *devpath, const char *pin, 1011read_rks(struct sk_usbhid *sk, const char *pin,
908 struct sk_resident_key ***rksp, size_t *nrksp) 1012 struct sk_resident_key ***rksp, size_t *nrksp)
909{ 1013{
910 int ret = SSH_SK_ERR_GENERAL, r = -1; 1014 int ret = SSH_SK_ERR_GENERAL, r = -1;
911 fido_dev_t *dev = NULL;
912 fido_credman_metadata_t *metadata = NULL; 1015 fido_credman_metadata_t *metadata = NULL;
913 fido_credman_rp_t *rp = NULL; 1016 fido_credman_rp_t *rp = NULL;
914 fido_credman_rk_t *rk = NULL; 1017 fido_credman_rk_t *rk = NULL;
@@ -916,30 +1019,25 @@ read_rks(const char *devpath, const char *pin,
916 const fido_cred_t *cred; 1019 const fido_cred_t *cred;
917 struct sk_resident_key *srk = NULL, **tmp; 1020 struct sk_resident_key *srk = NULL, **tmp;
918 1021
919 if ((dev = fido_dev_new()) == NULL) { 1022 if (pin == NULL) {
920 skdebug(__func__, "fido_dev_new failed"); 1023 skdebug(__func__, "no PIN specified");
921 return ret; 1024 ret = SSH_SK_ERR_PIN_REQUIRED;
922 } 1025 goto out;
923 if ((r = fido_dev_open(dev, devpath)) != FIDO_OK) {
924 skdebug(__func__, "fido_dev_open %s failed: %s",
925 devpath, fido_strerr(r));
926 fido_dev_free(&dev);
927 return ret;
928 } 1026 }
929 if ((metadata = fido_credman_metadata_new()) == NULL) { 1027 if ((metadata = fido_credman_metadata_new()) == NULL) {
930 skdebug(__func__, "alloc failed"); 1028 skdebug(__func__, "alloc failed");
931 goto out; 1029 goto out;
932 } 1030 }
933 1031
934 if ((r = fido_credman_get_dev_metadata(dev, metadata, pin)) != 0) { 1032 if ((r = fido_credman_get_dev_metadata(sk->dev, metadata, pin)) != 0) {
935 if (r == FIDO_ERR_INVALID_COMMAND) { 1033 if (r == FIDO_ERR_INVALID_COMMAND) {
936 skdebug(__func__, "device %s does not support " 1034 skdebug(__func__, "device %s does not support "
937 "resident keys", devpath); 1035 "resident keys", sk->path);
938 ret = 0; 1036 ret = 0;
939 goto out; 1037 goto out;
940 } 1038 }
941 skdebug(__func__, "get metadata for %s failed: %s", 1039 skdebug(__func__, "get metadata for %s failed: %s",
942 devpath, fido_strerr(r)); 1040 sk->path, fido_strerr(r));
943 ret = fidoerr_to_skerr(r); 1041 ret = fidoerr_to_skerr(r);
944 goto out; 1042 goto out;
945 } 1043 }
@@ -950,14 +1048,14 @@ read_rks(const char *devpath, const char *pin,
950 skdebug(__func__, "alloc rp failed"); 1048 skdebug(__func__, "alloc rp failed");
951 goto out; 1049 goto out;
952 } 1050 }
953 if ((r = fido_credman_get_dev_rp(dev, rp, pin)) != 0) { 1051 if ((r = fido_credman_get_dev_rp(sk->dev, rp, pin)) != 0) {
954 skdebug(__func__, "get RPs for %s failed: %s", 1052 skdebug(__func__, "get RPs for %s failed: %s",
955 devpath, fido_strerr(r)); 1053 sk->path, fido_strerr(r));
956 goto out; 1054 goto out;
957 } 1055 }
958 nrp = fido_credman_rp_count(rp); 1056 nrp = fido_credman_rp_count(rp);
959 skdebug(__func__, "Device %s has resident keys for %zu RPs", 1057 skdebug(__func__, "Device %s has resident keys for %zu RPs",
960 devpath, nrp); 1058 sk->path, nrp);
961 1059
962 /* Iterate over RP IDs that have resident keys */ 1060 /* Iterate over RP IDs that have resident keys */
963 for (i = 0; i < nrp; i++) { 1061 for (i = 0; i < nrp; i++) {
@@ -974,10 +1072,10 @@ read_rks(const char *devpath, const char *pin,
974 skdebug(__func__, "alloc rk failed"); 1072 skdebug(__func__, "alloc rk failed");
975 goto out; 1073 goto out;
976 } 1074 }
977 if ((r = fido_credman_get_dev_rk(dev, fido_credman_rp_id(rp, i), 1075 if ((r = fido_credman_get_dev_rk(sk->dev,
978 rk, pin)) != 0) { 1076 fido_credman_rp_id(rp, i), rk, pin)) != 0) {
979 skdebug(__func__, "get RKs for %s slot %zu failed: %s", 1077 skdebug(__func__, "get RKs for %s slot %zu failed: %s",
980 devpath, i, fido_strerr(r)); 1078 sk->path, i, fido_strerr(r));
981 goto out; 1079 goto out;
982 } 1080 }
983 nrk = fido_credman_rk_count(rk); 1081 nrk = fido_credman_rk_count(rk);
@@ -991,7 +1089,7 @@ read_rks(const char *devpath, const char *pin,
991 continue; 1089 continue;
992 } 1090 }
993 skdebug(__func__, "Device %s RP \"%s\" slot %zu: " 1091 skdebug(__func__, "Device %s RP \"%s\" slot %zu: "
994 "type %d flags 0x%02x prot 0x%02x", devpath, 1092 "type %d flags 0x%02x prot 0x%02x", sk->path,
995 fido_credman_rp_id(rp, i), j, fido_cred_type(cred), 1093 fido_credman_rp_id(rp, i), j, fido_cred_type(cred),
996 fido_cred_flags(cred), fido_cred_prot(cred)); 1094 fido_cred_flags(cred), fido_cred_prot(cred));
997 1095
@@ -1050,8 +1148,6 @@ read_rks(const char *devpath, const char *pin,
1050 } 1148 }
1051 fido_credman_rp_free(&rp); 1149 fido_credman_rp_free(&rp);
1052 fido_credman_rk_free(&rk); 1150 fido_credman_rk_free(&rk);
1053 fido_dev_close(dev);
1054 fido_dev_free(&dev);
1055 fido_credman_metadata_free(&metadata); 1151 fido_credman_metadata_free(&metadata);
1056 return ret; 1152 return ret;
1057} 1153}
@@ -1061,11 +1157,11 @@ sk_load_resident_keys(const char *pin, struct sk_option **options,
1061 struct sk_resident_key ***rksp, size_t *nrksp) 1157 struct sk_resident_key ***rksp, size_t *nrksp)
1062{ 1158{
1063 int ret = SSH_SK_ERR_GENERAL, r = -1; 1159 int ret = SSH_SK_ERR_GENERAL, r = -1;
1064 fido_dev_info_t *devlist = NULL; 1160 size_t i, nrks = 0;
1065 size_t i, ndev = 0, nrks = 0;
1066 const fido_dev_info_t *di;
1067 struct sk_resident_key **rks = NULL; 1161 struct sk_resident_key **rks = NULL;
1162 struct sk_usbhid *sk = NULL;
1068 char *device = NULL; 1163 char *device = NULL;
1164
1069 *rksp = NULL; 1165 *rksp = NULL;
1070 *nrksp = 0; 1166 *nrksp = 0;
1071 1167
@@ -1073,40 +1169,19 @@ sk_load_resident_keys(const char *pin, struct sk_option **options,
1073 1169
1074 if (check_sign_load_resident_options(options, &device) != 0) 1170 if (check_sign_load_resident_options(options, &device) != 0)
1075 goto out; /* error already logged */ 1171 goto out; /* error already logged */
1076 if (device != NULL) { 1172 if (device != NULL)
1077 skdebug(__func__, "trying %s", device); 1173 sk = sk_open(device);
1078 if ((r = read_rks(device, pin, &rks, &nrks)) != 0) { 1174 else
1079 skdebug(__func__, "read_rks failed for %s", device); 1175 sk = sk_probe(NULL, NULL, 0);
1080 ret = r; 1176 if (sk == NULL) {
1081 goto out; 1177 skdebug(__func__, "failed to find sk");
1082 } 1178 goto out;
1083 } else { 1179 }
1084 /* Try all devices */ 1180 skdebug(__func__, "trying %s", sk->path);
1085 if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) { 1181 if ((r = read_rks(sk, pin, &rks, &nrks)) != 0) {
1086 skdebug(__func__, "fido_dev_info_new failed"); 1182 skdebug(__func__, "read_rks failed for %s", sk->path);
1087 goto out; 1183 ret = r;
1088 } 1184 goto out;
1089 if ((r = fido_dev_info_manifest(devlist,
1090 MAX_FIDO_DEVICES, &ndev)) != FIDO_OK) {
1091 skdebug(__func__, "fido_dev_info_manifest failed: %s",
1092 fido_strerr(r));
1093 goto out;
1094 }
1095 for (i = 0; i < ndev; i++) {
1096 if ((di = fido_dev_info_ptr(devlist, i)) == NULL) {
1097 skdebug(__func__, "no dev info at %zu", i);
1098 continue;
1099 }
1100 skdebug(__func__, "trying %s", fido_dev_info_path(di));
1101 if ((r = read_rks(fido_dev_info_path(di), pin,
1102 &rks, &nrks)) != 0) {
1103 skdebug(__func__, "read_rks failed for %s",
1104 fido_dev_info_path(di));
1105 /* remember last error */
1106 ret = r;
1107 continue;
1108 }
1109 }
1110 } 1185 }
1111 /* success, unless we have no keys but a specific error */ 1186 /* success, unless we have no keys but a specific error */
1112 if (nrks > 0 || ret == SSH_SK_ERR_GENERAL) 1187 if (nrks > 0 || ret == SSH_SK_ERR_GENERAL)
@@ -1116,7 +1191,7 @@ sk_load_resident_keys(const char *pin, struct sk_option **options,
1116 rks = NULL; 1191 rks = NULL;
1117 nrks = 0; 1192 nrks = 0;
1118 out: 1193 out:
1119 free(device); 1194 sk_close(sk);
1120 for (i = 0; i < nrks; i++) { 1195 for (i = 0; i < nrks; i++) {
1121 free(rks[i]->application); 1196 free(rks[i]->application);
1122 freezero(rks[i]->key.public_key, rks[i]->key.public_key_len); 1197 freezero(rks[i]->key.public_key, rks[i]->key.public_key_len);
@@ -1124,7 +1199,6 @@ sk_load_resident_keys(const char *pin, struct sk_option **options,
1124 freezero(rks[i], sizeof(*rks[i])); 1199 freezero(rks[i], sizeof(*rks[i]));
1125 } 1200 }
1126 free(rks); 1201 free(rks);
1127 fido_dev_info_free(&devlist, MAX_FIDO_DEVICES);
1128 return ret; 1202 return ret;
1129} 1203}
1130 1204
diff --git a/ssh-keygen.c b/ssh-keygen.c
index 89ef9a143..1d6234c1c 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-keygen.c,v 1.416 2020/08/27 01:06:18 djm Exp $ */ 1/* $OpenBSD: ssh-keygen.c,v 1.417 2020/08/27 01:07:51 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -3632,6 +3632,11 @@ main(int argc, char **argv)
3632 fatal("Too many incorrect PINs"); 3632 fatal("Too many incorrect PINs");
3633 passphrase = read_passphrase("Enter PIN for " 3633 passphrase = read_passphrase("Enter PIN for "
3634 "authenticator: ", RP_ALLOW_STDIN); 3634 "authenticator: ", RP_ALLOW_STDIN);
3635 if (!quiet) {
3636 printf("You may need to touch your "
3637 "authenticator (again) to authorize "
3638 "key generation.\n");
3639 }
3635 } 3640 }
3636 if (passphrase != NULL) { 3641 if (passphrase != NULL) {
3637 freezero(passphrase, strlen(passphrase)); 3642 freezero(passphrase, strlen(passphrase));