summaryrefslogtreecommitdiff
path: root/sk-usbhid.c
diff options
context:
space:
mode:
Diffstat (limited to 'sk-usbhid.c')
-rw-r--r--sk-usbhid.c626
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
106struct 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 */
72uint32_t sk_api_version(void); 112uint32_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 */ 164static struct sk_usbhid *
125static char * 165sk_open(const char *path)
126pick_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
200static void
201sk_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
212static struct sk_usbhid **
213sk_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
242static void
243sk_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. */
158static int 252static int
159try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len, 253sk_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
268static int
269sk_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) */
303static int
304sha256_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. */
323static int
324sk_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 */ 372static struct sk_usbhid *
201static fido_dev_t * 373sk_select_by_cred(const fido_dev_info_t *devlist, size_t ndevs,
202find_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) { 403static struct sk_usbhid *
224 skdebug(__func__, "fido_dev_info_new failed"); 404sk_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");
450out:
451 sk_closev(skv, skvcnt);
452 return sk;
453}
264 454
265 out: 455static struct sk_usbhid *
266 if (devlist != NULL) 456sk_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) */
718static int
719sha256_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
737int 963int
738sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, 964sk_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
833static int 1064static int
834read_rks(const char *devpath, const char *pin, 1065read_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