summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2020-08-27 01:07:51 +0000
committerDamien Miller <djm@mindrot.org>2020-08-27 11:28:36 +1000
commit642e06d0df983fa2af85126cf4b23440bb2985bf (patch)
tree7115282d5778d4581b17a7fec07d7dcda64a7836
parent801c9f095e6d8b7b91aefd98f5001c652ea13488 (diff)
upstream: major rework of FIDO token selection logic
When PINs are in use and multiple FIDO tokens are attached to a host, we cannot just blast requests at all attached tokens with the PIN specified as this will cause the per-token PIN failure counter to increment. If this retry counter hits the token's limit (usually 3 attempts), then the token will lock itself and render all (web and SSH) of its keys invalid. We don't want this. So this reworks the key selection logic for the specific case of multiple keys being attached. When multiple keys are attached and the operation requires a PIN, then the user must touch the key that they wish to use first in order to identify it. This may require multiple touches, but only if there are multiple keys attached AND (usually) the operation requires a PIN. The usual case of a single key attached should be unaffected. Work by Pedro Martelletto; ok myself and markus@ OpenBSD-Commit-ID: 637d3049ced61b7a9ee796914bbc4843d999a864
-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));