1 /* $NetBSD: sk-usbhid.c,v 1.9 2023/10/25 20:19:57 christos Exp $ */
2 /* $OpenBSD: sk-usbhid.c,v 1.46 2023/03/28 06:12:38 dtucker Exp $ */
3
4 /*
5 * Copyright (c) 2019 Markus Friedl
6 * Copyright (c) 2020 Pedro Martelletto
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20 #include "includes.h"
21 __RCSID("$NetBSD: sk-usbhid.c,v 1.9 2023/10/25 20:19:57 christos Exp $");
22
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <stddef.h>
28 #include <stdarg.h>
29 #include <time.h>
30
31 #ifdef WITH_OPENSSL
32 #include <openssl/opensslv.h>
33 #include <openssl/crypto.h>
34 #include <openssl/bn.h>
35 #include <openssl/ec.h>
36 #include <openssl/ecdsa.h>
37 #include <openssl/evp.h>
38 #endif /* WITH_OPENSSL */
39
40 #include <fido.h>
41 #include <fido/credman.h>
42
43 #ifndef SK_STANDALONE
44 # include "log.h"
45 # include "xmalloc.h"
46 # include "misc.h"
47 /*
48 * If building as part of OpenSSH, then rename exported functions.
49 * This must be done before including sk-api.h.
50 */
51 # define sk_api_version ssh_sk_api_version
52 # define sk_enroll ssh_sk_enroll
53 # define sk_sign ssh_sk_sign
54 # define sk_load_resident_keys ssh_sk_load_resident_keys
55 #endif /* !SK_STANDALONE */
56
57 #include "sk-api.h"
58
59 /* #define SK_DEBUG 1 */
60
61 #ifdef SK_DEBUG
62 #define SSH_FIDO_INIT_ARG FIDO_DEBUG
63 #else
64 #define SSH_FIDO_INIT_ARG 0
65 #endif
66
67 #define MAX_FIDO_DEVICES 8
68 #define FIDO_POLL_MS 50
69 #define SELECT_MS 15000
70 #define POLL_SLEEP_NS 200000000
71
72 #ifndef FIDO_ERR_OPERATION_DENIED
73 #define FIDO_ERR_OPERATION_DENIED 0x27
74 #endif
75
76 struct sk_usbhid {
77 fido_dev_t *dev;
78 char *path;
79 };
80
81 /* Return the version of the middleware API */
82 uint32_t sk_api_version(void);
83
84 /* Enroll a U2F key (private key generation) */
85 int sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
86 const char *application, uint8_t flags, const char *pin,
87 struct sk_option **options, struct sk_enroll_response **enroll_response);
88
89 /* Sign a challenge */
90 int sk_sign(uint32_t alg, const uint8_t *data, size_t data_len,
91 const char *application, const uint8_t *key_handle, size_t key_handle_len,
92 uint8_t flags, const char *pin, struct sk_option **options,
93 struct sk_sign_response **sign_response);
94
95 /* Load resident keys */
96 int sk_load_resident_keys(const char *pin, struct sk_option **options,
97 struct sk_resident_key ***rks, size_t *nrks);
98
99 static void skdebug(const char *func, const char *fmt, ...)
100 __attribute__((__format__ (printf, 2, 3)));
101
102 static void
skdebug(const char * func,const char * fmt,...)103 skdebug(const char *func, const char *fmt, ...)
104 {
105 #if !defined(SK_STANDALONE)
106 char *msg;
107 va_list ap;
108
109 va_start(ap, fmt);
110 xvasprintf(&msg, fmt, ap);
111 va_end(ap);
112 debug("%s: %s", func, msg);
113 free(msg);
114 #elif defined(SK_DEBUG)
115 va_list ap;
116
117 va_start(ap, fmt);
118 fprintf(stderr, "%s: ", func);
119 vfprintf(stderr, fmt, ap);
120 fputc('\n', stderr);
121 va_end(ap);
122 #else
123 (void)func; /* XXX */
124 (void)fmt; /* XXX */
125 #endif
126 }
127
128 uint32_t
sk_api_version(void)129 sk_api_version(void)
130 {
131 return SSH_SK_VERSION_MAJOR;
132 }
133
134 static struct sk_usbhid *
sk_open(const char * path)135 sk_open(const char *path)
136 {
137 struct sk_usbhid *sk;
138 int r;
139
140 if (path == NULL) {
141 skdebug(__func__, "path == NULL");
142 return NULL;
143 }
144 if ((sk = calloc(1, sizeof(*sk))) == NULL) {
145 skdebug(__func__, "calloc sk failed");
146 return NULL;
147 }
148 if ((sk->path = strdup(path)) == NULL) {
149 skdebug(__func__, "strdup path failed");
150 free(sk);
151 return NULL;
152 }
153 if ((sk->dev = fido_dev_new()) == NULL) {
154 skdebug(__func__, "fido_dev_new failed");
155 free(sk->path);
156 free(sk);
157 return NULL;
158 }
159 if ((r = fido_dev_open(sk->dev, sk->path)) != FIDO_OK) {
160 skdebug(__func__, "fido_dev_open %s failed: %s", sk->path,
161 fido_strerr(r));
162 fido_dev_free(&sk->dev);
163 free(sk->path);
164 free(sk);
165 return NULL;
166 }
167 return sk;
168 }
169
170 static void
sk_close(struct sk_usbhid * sk)171 sk_close(struct sk_usbhid *sk)
172 {
173 if (sk == NULL)
174 return;
175 fido_dev_cancel(sk->dev); /* cancel any pending operation */
176 fido_dev_close(sk->dev);
177 fido_dev_free(&sk->dev);
178 free(sk->path);
179 free(sk);
180 }
181
182 static struct sk_usbhid **
sk_openv(const fido_dev_info_t * devlist,size_t ndevs,size_t * nopen)183 sk_openv(const fido_dev_info_t *devlist, size_t ndevs, size_t *nopen)
184 {
185 const fido_dev_info_t *di;
186 struct sk_usbhid **skv;
187 size_t i;
188
189 *nopen = 0;
190 if ((skv = calloc(ndevs, sizeof(*skv))) == NULL) {
191 skdebug(__func__, "calloc skv failed");
192 return NULL;
193 }
194 for (i = 0; i < ndevs; i++) {
195 if ((di = fido_dev_info_ptr(devlist, i)) == NULL)
196 skdebug(__func__, "fido_dev_info_ptr failed");
197 else if ((skv[*nopen] = sk_open(fido_dev_info_path(di))) == NULL)
198 skdebug(__func__, "sk_open failed");
199 else
200 (*nopen)++;
201 }
202 if (*nopen == 0) {
203 for (i = 0; i < ndevs; i++)
204 sk_close(skv[i]);
205 free(skv);
206 skv = NULL;
207 }
208
209 return skv;
210 }
211
212 static void
sk_closev(struct sk_usbhid ** skv,size_t nsk)213 sk_closev(struct sk_usbhid **skv, size_t nsk)
214 {
215 size_t i;
216
217 for (i = 0; i < nsk; i++)
218 sk_close(skv[i]);
219 free(skv);
220 }
221
222 static int
sk_touch_begin(struct sk_usbhid ** skv,size_t nsk)223 sk_touch_begin(struct sk_usbhid **skv, size_t nsk)
224 {
225 size_t i, ok = 0;
226 int r;
227
228 for (i = 0; i < nsk; i++)
229 if ((r = fido_dev_get_touch_begin(skv[i]->dev)) != FIDO_OK)
230 skdebug(__func__, "fido_dev_get_touch_begin %s failed:"
231 " %s", skv[i]->path, fido_strerr(r));
232 else
233 ok++;
234
235 return ok ? 0 : -1;
236 }
237
238 static int
sk_touch_poll(struct sk_usbhid ** skv,size_t nsk,int * touch,size_t * idx)239 sk_touch_poll(struct sk_usbhid **skv, size_t nsk, int *touch, size_t *idx)
240 {
241 struct timespec ts_pause;
242 size_t npoll, i;
243 int r;
244
245 ts_pause.tv_sec = 0;
246 ts_pause.tv_nsec = POLL_SLEEP_NS;
247 nanosleep(&ts_pause, NULL);
248 npoll = nsk;
249 for (i = 0; i < nsk; i++) {
250 if (skv[i] == NULL)
251 continue; /* device discarded */
252 skdebug(__func__, "polling %s", skv[i]->path);
253 if ((r = fido_dev_get_touch_status(skv[i]->dev, touch,
254 FIDO_POLL_MS)) != FIDO_OK) {
255 skdebug(__func__, "fido_dev_get_touch_status %s: %s",
256 skv[i]->path, fido_strerr(r));
257 sk_close(skv[i]); /* discard device */
258 skv[i] = NULL;
259 if (--npoll == 0) {
260 skdebug(__func__, "no device left to poll");
261 return -1;
262 }
263 } else if (*touch) {
264 *idx = i;
265 return 0;
266 }
267 }
268 *touch = 0;
269 return 0;
270 }
271
272 /* Check if the specified key handle exists on a given sk. */
273 static int
sk_try(const struct sk_usbhid * sk,const char * application,const uint8_t * key_handle,size_t key_handle_len)274 sk_try(const struct sk_usbhid *sk, const char *application,
275 const uint8_t *key_handle, size_t key_handle_len)
276 {
277 fido_assert_t *assert = NULL;
278 int r = FIDO_ERR_INTERNAL;
279 uint8_t message[32];
280
281 memset(message, '\0', sizeof(message));
282 if ((assert = fido_assert_new()) == NULL) {
283 skdebug(__func__, "fido_assert_new failed");
284 goto out;
285 }
286 /* generate an invalid signature on FIDO2 tokens */
287 if ((r = fido_assert_set_clientdata(assert, message,
288 sizeof(message))) != FIDO_OK) {
289 skdebug(__func__, "fido_assert_set_clientdata: %s",
290 fido_strerr(r));
291 goto out;
292 }
293 if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK) {
294 skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r));
295 goto out;
296 }
297 if ((r = fido_assert_allow_cred(assert, key_handle,
298 key_handle_len)) != FIDO_OK) {
299 skdebug(__func__, "fido_assert_allow_cred: %s", fido_strerr(r));
300 goto out;
301 }
302 if ((r = fido_assert_set_up(assert, FIDO_OPT_FALSE)) != FIDO_OK) {
303 skdebug(__func__, "fido_assert_up: %s", fido_strerr(r));
304 goto out;
305 }
306 r = fido_dev_get_assert(sk->dev, assert, NULL);
307 skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
308 if (r == FIDO_ERR_USER_PRESENCE_REQUIRED) {
309 /* U2F tokens may return this */
310 r = FIDO_OK;
311 }
312 out:
313 fido_assert_free(&assert);
314
315 return r != FIDO_OK ? -1 : 0;
316 }
317
318 static int
check_sk_options(fido_dev_t * dev,const char * opt,int * ret)319 check_sk_options(fido_dev_t *dev, const char *opt, int *ret)
320 {
321 fido_cbor_info_t *info;
322 char * const *name;
323 const bool *value;
324 size_t len, i;
325 int r;
326
327 *ret = -1;
328
329 if (!fido_dev_is_fido2(dev)) {
330 skdebug(__func__, "device is not fido2");
331 return 0;
332 }
333 if ((info = fido_cbor_info_new()) == NULL) {
334 skdebug(__func__, "fido_cbor_info_new failed");
335 return -1;
336 }
337 if ((r = fido_dev_get_cbor_info(dev, info)) != FIDO_OK) {
338 skdebug(__func__, "fido_dev_get_cbor_info: %s", fido_strerr(r));
339 fido_cbor_info_free(&info);
340 return -1;
341 }
342 name = fido_cbor_info_options_name_ptr(info);
343 value = fido_cbor_info_options_value_ptr(info);
344 len = fido_cbor_info_options_len(info);
345 for (i = 0; i < len; i++) {
346 if (!strcmp(name[i], opt)) {
347 *ret = value[i];
348 break;
349 }
350 }
351 fido_cbor_info_free(&info);
352 if (*ret == -1)
353 skdebug(__func__, "option %s is unknown", opt);
354 else
355 skdebug(__func__, "option %s is %s", opt, *ret ? "on" : "off");
356
357 return 0;
358 }
359
360 static struct sk_usbhid *
sk_select_by_cred(const fido_dev_info_t * devlist,size_t ndevs,const char * application,const uint8_t * key_handle,size_t key_handle_len)361 sk_select_by_cred(const fido_dev_info_t *devlist, size_t ndevs,
362 const char *application, const uint8_t *key_handle, size_t key_handle_len)
363 {
364 struct sk_usbhid **skv, *sk;
365 size_t skvcnt, i;
366 int internal_uv;
367
368 if ((skv = sk_openv(devlist, ndevs, &skvcnt)) == NULL) {
369 skdebug(__func__, "sk_openv failed");
370 return NULL;
371 }
372 if (skvcnt == 1 && check_sk_options(skv[0]->dev, "uv",
373 &internal_uv) == 0 && internal_uv != -1) {
374 sk = skv[0];
375 skv[0] = NULL;
376 goto out;
377 }
378 sk = NULL;
379 for (i = 0; i < skvcnt; i++) {
380 if (sk_try(skv[i], application, key_handle,
381 key_handle_len) == 0) {
382 sk = skv[i];
383 skv[i] = NULL;
384 skdebug(__func__, "found key in %s", sk->path);
385 break;
386 }
387 }
388 out:
389 sk_closev(skv, skvcnt);
390 return sk;
391 }
392
393 static struct sk_usbhid *
sk_select_by_touch(const fido_dev_info_t * devlist,size_t ndevs)394 sk_select_by_touch(const fido_dev_info_t *devlist, size_t ndevs)
395 {
396 struct sk_usbhid **skv, *sk;
397 struct timeval tv_start, tv_now, tv_delta;
398 size_t skvcnt, idx;
399 int touch, ms_remain;
400
401 if ((skv = sk_openv(devlist, ndevs, &skvcnt)) == NULL) {
402 skdebug(__func__, "sk_openv failed");
403 return NULL;
404 }
405 sk = NULL;
406 if (skvcnt < 2) {
407 if (skvcnt == 1) {
408 /* single candidate */
409 sk = skv[0];
410 skv[0] = NULL;
411 }
412 goto out;
413 }
414 if (sk_touch_begin(skv, skvcnt) == -1) {
415 skdebug(__func__, "sk_touch_begin failed");
416 goto out;
417 }
418 monotime_tv(&tv_start);
419 do {
420 if (sk_touch_poll(skv, skvcnt, &touch, &idx) == -1) {
421 skdebug(__func__, "sk_touch_poll failed");
422 goto out;
423 }
424 if (touch) {
425 sk = skv[idx];
426 skv[idx] = NULL;
427 goto out;
428 }
429 monotime_tv(&tv_now);
430 timersub(&tv_now, &tv_start, &tv_delta);
431 ms_remain = SELECT_MS - tv_delta.tv_sec * 1000 -
432 tv_delta.tv_usec / 1000;
433 } while (ms_remain >= FIDO_POLL_MS);
434 skdebug(__func__, "timeout");
435 out:
436 sk_closev(skv, skvcnt);
437 return sk;
438 }
439
440 static struct sk_usbhid *
sk_probe(const char * application,const uint8_t * key_handle,size_t key_handle_len,int probe_resident)441 sk_probe(const char *application, const uint8_t *key_handle,
442 size_t key_handle_len, int probe_resident)
443 {
444 struct sk_usbhid *sk;
445 fido_dev_info_t *devlist;
446 size_t ndevs;
447 int r;
448
449 if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) {
450 skdebug(__func__, "fido_dev_info_new failed");
451 return NULL;
452 }
453 if ((r = fido_dev_info_manifest(devlist, MAX_FIDO_DEVICES,
454 &ndevs)) != FIDO_OK) {
455 skdebug(__func__, "fido_dev_info_manifest failed: %s",
456 fido_strerr(r));
457 fido_dev_info_free(&devlist, MAX_FIDO_DEVICES);
458 return NULL;
459 }
460 skdebug(__func__, "%zu device(s) detected", ndevs);
461 if (ndevs == 0) {
462 sk = NULL;
463 } else if (application != NULL && key_handle != NULL) {
464 skdebug(__func__, "selecting sk by cred");
465 sk = sk_select_by_cred(devlist, ndevs, application, key_handle,
466 key_handle_len);
467 } else {
468 skdebug(__func__, "selecting sk by touch");
469 sk = sk_select_by_touch(devlist, ndevs);
470 }
471 fido_dev_info_free(&devlist, MAX_FIDO_DEVICES);
472 return sk;
473 }
474
475 #ifdef WITH_OPENSSL
476 /*
477 * The key returned via fido_cred_pubkey_ptr() is in affine coordinates,
478 * but the API expects a SEC1 octet string.
479 */
480 static int
pack_public_key_ecdsa(const fido_cred_t * cred,struct sk_enroll_response * response)481 pack_public_key_ecdsa(const fido_cred_t *cred,
482 struct sk_enroll_response *response)
483 {
484 const uint8_t *ptr;
485 BIGNUM *x = NULL, *y = NULL;
486 EC_POINT *q = NULL;
487 EC_GROUP *g = NULL;
488 int ret = -1;
489
490 response->public_key = NULL;
491 response->public_key_len = 0;
492
493 if ((x = BN_new()) == NULL ||
494 (y = BN_new()) == NULL ||
495 (g = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)) == NULL ||
496 (q = EC_POINT_new(g)) == NULL) {
497 skdebug(__func__, "libcrypto setup failed");
498 goto out;
499 }
500 if ((ptr = fido_cred_pubkey_ptr(cred)) == NULL) {
501 skdebug(__func__, "fido_cred_pubkey_ptr failed");
502 goto out;
503 }
504 if (fido_cred_pubkey_len(cred) != 64) {
505 skdebug(__func__, "bad fido_cred_pubkey_len %zu",
506 fido_cred_pubkey_len(cred));
507 goto out;
508 }
509
510 if (BN_bin2bn(ptr, 32, x) == NULL ||
511 BN_bin2bn(ptr + 32, 32, y) == NULL) {
512 skdebug(__func__, "BN_bin2bn failed");
513 goto out;
514 }
515 if (EC_POINT_set_affine_coordinates_GFp(g, q, x, y, NULL) != 1) {
516 skdebug(__func__, "EC_POINT_set_affine_coordinates_GFp failed");
517 goto out;
518 }
519 response->public_key_len = EC_POINT_point2oct(g, q,
520 POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
521 if (response->public_key_len == 0 || response->public_key_len > 2048) {
522 skdebug(__func__, "bad pubkey length %zu",
523 response->public_key_len);
524 goto out;
525 }
526 if ((response->public_key = malloc(response->public_key_len)) == NULL) {
527 skdebug(__func__, "malloc pubkey failed");
528 goto out;
529 }
530 if (EC_POINT_point2oct(g, q, POINT_CONVERSION_UNCOMPRESSED,
531 response->public_key, response->public_key_len, NULL) == 0) {
532 skdebug(__func__, "EC_POINT_point2oct failed");
533 goto out;
534 }
535 /* success */
536 ret = 0;
537 out:
538 if (ret != 0 && response->public_key != NULL) {
539 memset(response->public_key, 0, response->public_key_len);
540 free(response->public_key);
541 response->public_key = NULL;
542 }
543 EC_POINT_free(q);
544 EC_GROUP_free(g);
545 BN_clear_free(x);
546 BN_clear_free(y);
547 return ret;
548 }
549 #endif /* WITH_OPENSSL */
550
551 static int
pack_public_key_ed25519(const fido_cred_t * cred,struct sk_enroll_response * response)552 pack_public_key_ed25519(const fido_cred_t *cred,
553 struct sk_enroll_response *response)
554 {
555 const uint8_t *ptr;
556 size_t len;
557 int ret = -1;
558
559 response->public_key = NULL;
560 response->public_key_len = 0;
561
562 if ((len = fido_cred_pubkey_len(cred)) != 32) {
563 skdebug(__func__, "bad fido_cred_pubkey_len len %zu", len);
564 goto out;
565 }
566 if ((ptr = fido_cred_pubkey_ptr(cred)) == NULL) {
567 skdebug(__func__, "fido_cred_pubkey_ptr failed");
568 goto out;
569 }
570 response->public_key_len = len;
571 if ((response->public_key = malloc(response->public_key_len)) == NULL) {
572 skdebug(__func__, "malloc pubkey failed");
573 goto out;
574 }
575 memcpy(response->public_key, ptr, len);
576 ret = 0;
577 out:
578 if (ret != 0)
579 free(response->public_key);
580 return ret;
581 }
582
583 static int
pack_public_key(uint32_t alg,const fido_cred_t * cred,struct sk_enroll_response * response)584 pack_public_key(uint32_t alg, const fido_cred_t *cred,
585 struct sk_enroll_response *response)
586 {
587 switch(alg) {
588 #ifdef WITH_OPENSSL
589 case SSH_SK_ECDSA:
590 return pack_public_key_ecdsa(cred, response);
591 #endif /* WITH_OPENSSL */
592 case SSH_SK_ED25519:
593 return pack_public_key_ed25519(cred, response);
594 default:
595 return -1;
596 }
597 }
598
599 static int
fidoerr_to_skerr(int fidoerr)600 fidoerr_to_skerr(int fidoerr)
601 {
602 switch (fidoerr) {
603 case FIDO_ERR_UNSUPPORTED_OPTION:
604 case FIDO_ERR_UNSUPPORTED_ALGORITHM:
605 return SSH_SK_ERR_UNSUPPORTED;
606 case FIDO_ERR_PIN_REQUIRED:
607 case FIDO_ERR_PIN_INVALID:
608 case FIDO_ERR_OPERATION_DENIED:
609 return SSH_SK_ERR_PIN_REQUIRED;
610 default:
611 return -1;
612 }
613 }
614
615 static int
check_enroll_options(struct sk_option ** options,char ** devicep,uint8_t * user_id,size_t user_id_len)616 check_enroll_options(struct sk_option **options, char **devicep,
617 uint8_t *user_id, size_t user_id_len)
618 {
619 size_t i;
620
621 if (options == NULL)
622 return 0;
623 for (i = 0; options[i] != NULL; i++) {
624 if (strcmp(options[i]->name, "device") == 0) {
625 if ((*devicep = strdup(options[i]->value)) == NULL) {
626 skdebug(__func__, "strdup device failed");
627 return -1;
628 }
629 skdebug(__func__, "requested device %s", *devicep);
630 } else if (strcmp(options[i]->name, "user") == 0) {
631 if (strlcpy((char *)user_id, options[i]->value, user_id_len) >=
632 user_id_len) {
633 skdebug(__func__, "user too long");
634 return -1;
635 }
636 skdebug(__func__, "requested user %s",
637 (char *)user_id);
638 } else {
639 skdebug(__func__, "requested unsupported option %s",
640 options[i]->name);
641 if (options[i]->required) {
642 skdebug(__func__, "unknown required option");
643 return -1;
644 }
645 }
646 }
647 return 0;
648 }
649
650 static int
key_lookup(fido_dev_t * dev,const char * application,const uint8_t * user_id,size_t user_id_len,const char * pin)651 key_lookup(fido_dev_t *dev, const char *application, const uint8_t *user_id,
652 size_t user_id_len, const char *pin)
653 {
654 fido_assert_t *assert = NULL;
655 uint8_t message[32];
656 int r = FIDO_ERR_INTERNAL;
657 int sk_supports_uv, uv;
658 size_t i;
659
660 memset(message, '\0', sizeof(message));
661 if ((assert = fido_assert_new()) == NULL) {
662 skdebug(__func__, "fido_assert_new failed");
663 goto out;
664 }
665 /* generate an invalid signature on FIDO2 tokens */
666 if ((r = fido_assert_set_clientdata(assert, message,
667 sizeof(message))) != FIDO_OK) {
668 skdebug(__func__, "fido_assert_set_clientdata: %s",
669 fido_strerr(r));
670 goto out;
671 }
672 if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK) {
673 skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r));
674 goto out;
675 }
676 if ((r = fido_assert_set_up(assert, FIDO_OPT_FALSE)) != FIDO_OK) {
677 skdebug(__func__, "fido_assert_set_up: %s", fido_strerr(r));
678 goto out;
679 }
680 uv = FIDO_OPT_OMIT;
681 if (pin == NULL && check_sk_options(dev, "uv", &sk_supports_uv) == 0 &&
682 sk_supports_uv != -1)
683 uv = FIDO_OPT_TRUE;
684 if ((r = fido_assert_set_uv(assert, uv)) != FIDO_OK) {
685 skdebug(__func__, "fido_assert_set_uv: %s", fido_strerr(r));
686 goto out;
687 }
688 if ((r = fido_dev_get_assert(dev, assert, pin)) != FIDO_OK) {
689 skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
690 goto out;
691 }
692 r = FIDO_ERR_NO_CREDENTIALS;
693 skdebug(__func__, "%zu signatures returned", fido_assert_count(assert));
694 for (i = 0; i < fido_assert_count(assert); i++) {
695 if (fido_assert_user_id_len(assert, i) == user_id_len &&
696 memcmp(fido_assert_user_id_ptr(assert, i), user_id,
697 user_id_len) == 0) {
698 skdebug(__func__, "credential exists");
699 r = FIDO_OK;
700 goto out;
701 }
702 }
703 out:
704 fido_assert_free(&assert);
705
706 return r;
707 }
708
709 int
sk_enroll(uint32_t alg,const uint8_t * challenge,size_t challenge_len,const char * application,uint8_t flags,const char * pin,struct sk_option ** options,struct sk_enroll_response ** enroll_response)710 sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
711 const char *application, uint8_t flags, const char *pin,
712 struct sk_option **options, struct sk_enroll_response **enroll_response)
713 {
714 fido_cred_t *cred = NULL;
715 const uint8_t *ptr;
716 uint8_t user_id[32];
717 struct sk_usbhid *sk = NULL;
718 struct sk_enroll_response *response = NULL;
719 size_t len;
720 int credprot;
721 int cose_alg;
722 int ret = SSH_SK_ERR_GENERAL;
723 int r;
724 char *device = NULL;
725
726 fido_init(SSH_FIDO_INIT_ARG);
727
728 if (enroll_response == NULL) {
729 skdebug(__func__, "enroll_response == NULL");
730 goto out;
731 }
732 *enroll_response = NULL;
733 memset(user_id, 0, sizeof(user_id));
734 if (check_enroll_options(options, &device, user_id,
735 sizeof(user_id)) != 0)
736 goto out; /* error already logged */
737
738 switch(alg) {
739 #ifdef WITH_OPENSSL
740 case SSH_SK_ECDSA:
741 cose_alg = COSE_ES256;
742 break;
743 #endif /* WITH_OPENSSL */
744 case SSH_SK_ED25519:
745 cose_alg = COSE_EDDSA;
746 break;
747 default:
748 skdebug(__func__, "unsupported key type %d", alg);
749 goto out;
750 }
751 if (device != NULL)
752 sk = sk_open(device);
753 else
754 sk = sk_probe(NULL, NULL, 0, 0);
755 if (sk == NULL) {
756 ret = SSH_SK_ERR_DEVICE_NOT_FOUND;
757 skdebug(__func__, "failed to find sk");
758 goto out;
759 }
760 skdebug(__func__, "using device %s", sk->path);
761 if ((flags & SSH_SK_RESIDENT_KEY) != 0 &&
762 (flags & SSH_SK_FORCE_OPERATION) == 0 &&
763 (r = key_lookup(sk->dev, application, user_id, sizeof(user_id),
764 pin)) != FIDO_ERR_NO_CREDENTIALS) {
765 if (r != FIDO_OK) {
766 ret = fidoerr_to_skerr(r);
767 skdebug(__func__, "key_lookup failed");
768 } else {
769 ret = SSH_SK_ERR_CREDENTIAL_EXISTS;
770 skdebug(__func__, "key exists");
771 }
772 goto out;
773 }
774 if ((cred = fido_cred_new()) == NULL) {
775 skdebug(__func__, "fido_cred_new failed");
776 goto out;
777 }
778 if ((r = fido_cred_set_type(cred, cose_alg)) != FIDO_OK) {
779 skdebug(__func__, "fido_cred_set_type: %s", fido_strerr(r));
780 goto out;
781 }
782 if ((r = fido_cred_set_clientdata(cred,
783 challenge, challenge_len)) != FIDO_OK) {
784 skdebug(__func__, "fido_cred_set_clientdata: %s",
785 fido_strerr(r));
786 goto out;
787 }
788 if ((r = fido_cred_set_rk(cred, (flags & SSH_SK_RESIDENT_KEY) != 0 ?
789 FIDO_OPT_TRUE : FIDO_OPT_OMIT)) != FIDO_OK) {
790 skdebug(__func__, "fido_cred_set_rk: %s", fido_strerr(r));
791 goto out;
792 }
793 if ((r = fido_cred_set_user(cred, user_id, sizeof(user_id),
794 "openssh", "openssh", NULL)) != FIDO_OK) {
795 skdebug(__func__, "fido_cred_set_user: %s", fido_strerr(r));
796 goto out;
797 }
798 if ((r = fido_cred_set_rp(cred, application, NULL)) != FIDO_OK) {
799 skdebug(__func__, "fido_cred_set_rp: %s", fido_strerr(r));
800 goto out;
801 }
802 if ((flags & (SSH_SK_RESIDENT_KEY|SSH_SK_USER_VERIFICATION_REQD)) != 0) {
803 if (!fido_dev_supports_cred_prot(sk->dev)) {
804 skdebug(__func__, "%s does not support credprot, "
805 "refusing to create unprotected "
806 "resident/verify-required key", sk->path);
807 ret = SSH_SK_ERR_UNSUPPORTED;
808 goto out;
809 }
810 if ((flags & SSH_SK_USER_VERIFICATION_REQD))
811 credprot = FIDO_CRED_PROT_UV_REQUIRED;
812 else
813 credprot = FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID;
814
815 if ((r = fido_cred_set_prot(cred, credprot)) != FIDO_OK) {
816 skdebug(__func__, "fido_cred_set_prot: %s",
817 fido_strerr(r));
818 ret = fidoerr_to_skerr(r);
819 goto out;
820 }
821 }
822 if ((r = fido_dev_make_cred(sk->dev, cred, pin)) != FIDO_OK) {
823 skdebug(__func__, "fido_dev_make_cred: %s", fido_strerr(r));
824 ret = fidoerr_to_skerr(r);
825 goto out;
826 }
827 if (fido_cred_x5c_ptr(cred) != NULL) {
828 if ((r = fido_cred_verify(cred)) != FIDO_OK) {
829 skdebug(__func__, "fido_cred_verify: %s",
830 fido_strerr(r));
831 goto out;
832 }
833 } else {
834 skdebug(__func__, "self-attested credential");
835 if ((r = fido_cred_verify_self(cred)) != FIDO_OK) {
836 skdebug(__func__, "fido_cred_verify_self: %s",
837 fido_strerr(r));
838 goto out;
839 }
840 }
841 if ((response = calloc(1, sizeof(*response))) == NULL) {
842 skdebug(__func__, "calloc response failed");
843 goto out;
844 }
845 response->flags = flags;
846 if (pack_public_key(alg, cred, response) != 0) {
847 skdebug(__func__, "pack_public_key failed");
848 goto out;
849 }
850 if ((ptr = fido_cred_id_ptr(cred)) != NULL) {
851 len = fido_cred_id_len(cred);
852 if ((response->key_handle = calloc(1, len)) == NULL) {
853 skdebug(__func__, "calloc key handle failed");
854 goto out;
855 }
856 memcpy(response->key_handle, ptr, len);
857 response->key_handle_len = len;
858 }
859 if ((ptr = fido_cred_sig_ptr(cred)) != NULL) {
860 len = fido_cred_sig_len(cred);
861 if ((response->signature = calloc(1, len)) == NULL) {
862 skdebug(__func__, "calloc signature failed");
863 goto out;
864 }
865 memcpy(response->signature, ptr, len);
866 response->signature_len = len;
867 }
868 if ((ptr = fido_cred_x5c_ptr(cred)) != NULL) {
869 len = fido_cred_x5c_len(cred);
870 skdebug(__func__, "attestation cert len=%zu", len);
871 if ((response->attestation_cert = calloc(1, len)) == NULL) {
872 skdebug(__func__, "calloc attestation cert failed");
873 goto out;
874 }
875 memcpy(response->attestation_cert, ptr, len);
876 response->attestation_cert_len = len;
877 }
878 if ((ptr = fido_cred_authdata_ptr(cred)) != NULL) {
879 len = fido_cred_authdata_len(cred);
880 skdebug(__func__, "authdata len=%zu", len);
881 if ((response->authdata = calloc(1, len)) == NULL) {
882 skdebug(__func__, "calloc authdata failed");
883 goto out;
884 }
885 memcpy(response->authdata, ptr, len);
886 response->authdata_len = len;
887 }
888 *enroll_response = response;
889 response = NULL;
890 ret = 0;
891 out:
892 free(device);
893 if (response != NULL) {
894 free(response->public_key);
895 free(response->key_handle);
896 free(response->signature);
897 free(response->attestation_cert);
898 free(response->authdata);
899 free(response);
900 }
901 sk_close(sk);
902 fido_cred_free(&cred);
903 return ret;
904 }
905
906 #ifdef WITH_OPENSSL
907 static int
pack_sig_ecdsa(fido_assert_t * assert,struct sk_sign_response * response)908 pack_sig_ecdsa(fido_assert_t *assert, struct sk_sign_response *response)
909 {
910 ECDSA_SIG *sig = NULL;
911 const BIGNUM *sig_r, *sig_s;
912 const unsigned char *cp;
913 size_t sig_len;
914 int ret = -1;
915
916 cp = fido_assert_sig_ptr(assert, 0);
917 sig_len = fido_assert_sig_len(assert, 0);
918 if ((sig = d2i_ECDSA_SIG(NULL, &cp, sig_len)) == NULL) {
919 skdebug(__func__, "d2i_ECDSA_SIG failed");
920 goto out;
921 }
922 ECDSA_SIG_get0(sig, &sig_r, &sig_s);
923 response->sig_r_len = BN_num_bytes(sig_r);
924 response->sig_s_len = BN_num_bytes(sig_s);
925 if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL ||
926 (response->sig_s = calloc(1, response->sig_s_len)) == NULL) {
927 skdebug(__func__, "calloc signature failed");
928 goto out;
929 }
930 BN_bn2bin(sig_r, response->sig_r);
931 BN_bn2bin(sig_s, response->sig_s);
932 ret = 0;
933 out:
934 ECDSA_SIG_free(sig);
935 if (ret != 0) {
936 free(response->sig_r);
937 free(response->sig_s);
938 response->sig_r = NULL;
939 response->sig_s = NULL;
940 }
941 return ret;
942 }
943 #endif /* WITH_OPENSSL */
944
945 static int
pack_sig_ed25519(fido_assert_t * assert,struct sk_sign_response * response)946 pack_sig_ed25519(fido_assert_t *assert, struct sk_sign_response *response)
947 {
948 const unsigned char *ptr;
949 size_t len;
950 int ret = -1;
951
952 ptr = fido_assert_sig_ptr(assert, 0);
953 len = fido_assert_sig_len(assert, 0);
954 if (len != 64) {
955 skdebug(__func__, "bad length %zu", len);
956 goto out;
957 }
958 response->sig_r_len = len;
959 if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL) {
960 skdebug(__func__, "calloc signature failed");
961 goto out;
962 }
963 memcpy(response->sig_r, ptr, len);
964 ret = 0;
965 out:
966 if (ret != 0) {
967 free(response->sig_r);
968 response->sig_r = NULL;
969 }
970 return ret;
971 }
972
973 static int
pack_sig(uint32_t alg,fido_assert_t * assert,struct sk_sign_response * response)974 pack_sig(uint32_t alg, fido_assert_t *assert,
975 struct sk_sign_response *response)
976 {
977 switch(alg) {
978 #ifdef WITH_OPENSSL
979 case SSH_SK_ECDSA:
980 return pack_sig_ecdsa(assert, response);
981 #endif /* WITH_OPENSSL */
982 case SSH_SK_ED25519:
983 return pack_sig_ed25519(assert, response);
984 default:
985 return -1;
986 }
987 }
988
989 /* Checks sk_options for sk_sign() and sk_load_resident_keys() */
990 static int
check_sign_load_resident_options(struct sk_option ** options,char ** devicep)991 check_sign_load_resident_options(struct sk_option **options, char **devicep)
992 {
993 size_t i;
994
995 if (options == NULL)
996 return 0;
997 for (i = 0; options[i] != NULL; i++) {
998 if (strcmp(options[i]->name, "device") == 0) {
999 if ((*devicep = strdup(options[i]->value)) == NULL) {
1000 skdebug(__func__, "strdup device failed");
1001 return -1;
1002 }
1003 skdebug(__func__, "requested device %s", *devicep);
1004 } else {
1005 skdebug(__func__, "requested unsupported option %s",
1006 options[i]->name);
1007 if (options[i]->required) {
1008 skdebug(__func__, "unknown required option");
1009 return -1;
1010 }
1011 }
1012 }
1013 return 0;
1014 }
1015
1016 int
sk_sign(uint32_t alg,const uint8_t * data,size_t datalen,const char * application,const uint8_t * key_handle,size_t key_handle_len,uint8_t flags,const char * pin,struct sk_option ** options,struct sk_sign_response ** sign_response)1017 sk_sign(uint32_t alg, const uint8_t *data, size_t datalen,
1018 const char *application,
1019 const uint8_t *key_handle, size_t key_handle_len,
1020 uint8_t flags, const char *pin, struct sk_option **options,
1021 struct sk_sign_response **sign_response)
1022 {
1023 fido_assert_t *assert = NULL;
1024 char *device = NULL;
1025 struct sk_usbhid *sk = NULL;
1026 struct sk_sign_response *response = NULL;
1027 int ret = SSH_SK_ERR_GENERAL, internal_uv;
1028 int r;
1029
1030 fido_init(SSH_FIDO_INIT_ARG);
1031
1032 if (sign_response == NULL) {
1033 skdebug(__func__, "sign_response == NULL");
1034 goto out;
1035 }
1036 *sign_response = NULL;
1037 if (check_sign_load_resident_options(options, &device) != 0)
1038 goto out; /* error already logged */
1039 if (device != NULL)
1040 sk = sk_open(device);
1041 else if (pin != NULL || (flags & SSH_SK_USER_VERIFICATION_REQD))
1042 sk = sk_probe(NULL, NULL, 0, 0);
1043 else
1044 sk = sk_probe(application, key_handle, key_handle_len, 0);
1045 if (sk == NULL) {
1046 ret = SSH_SK_ERR_DEVICE_NOT_FOUND;
1047 skdebug(__func__, "failed to find sk");
1048 goto out;
1049 }
1050 if ((assert = fido_assert_new()) == NULL) {
1051 skdebug(__func__, "fido_assert_new failed");
1052 goto out;
1053 }
1054 if ((r = fido_assert_set_clientdata(assert,
1055 data, datalen)) != FIDO_OK) {
1056 skdebug(__func__, "fido_assert_set_clientdata: %s",
1057 fido_strerr(r));
1058 goto out;
1059 }
1060 if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK) {
1061 skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r));
1062 goto out;
1063 }
1064 if ((r = fido_assert_allow_cred(assert, key_handle,
1065 key_handle_len)) != FIDO_OK) {
1066 skdebug(__func__, "fido_assert_allow_cred: %s", fido_strerr(r));
1067 goto out;
1068 }
1069 if ((r = fido_assert_set_up(assert,
1070 (flags & SSH_SK_USER_PRESENCE_REQD) ?
1071 FIDO_OPT_TRUE : FIDO_OPT_FALSE)) != FIDO_OK) {
1072 skdebug(__func__, "fido_assert_set_up: %s", fido_strerr(r));
1073 goto out;
1074 }
1075 if (pin == NULL && (flags & SSH_SK_USER_VERIFICATION_REQD)) {
1076 if (check_sk_options(sk->dev, "uv", &internal_uv) < 0 ||
1077 internal_uv != 1) {
1078 skdebug(__func__, "check_sk_options uv");
1079 ret = SSH_SK_ERR_PIN_REQUIRED;
1080 goto out;
1081 }
1082 if ((r = fido_assert_set_uv(assert,
1083 FIDO_OPT_TRUE)) != FIDO_OK) {
1084 skdebug(__func__, "fido_assert_set_uv: %s",
1085 fido_strerr(r));
1086 ret = fidoerr_to_skerr(r);
1087 goto out;
1088 }
1089 }
1090 if ((r = fido_dev_get_assert(sk->dev, assert, pin)) != FIDO_OK) {
1091 skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
1092 ret = fidoerr_to_skerr(r);
1093 goto out;
1094 }
1095 if ((response = calloc(1, sizeof(*response))) == NULL) {
1096 skdebug(__func__, "calloc response failed");
1097 goto out;
1098 }
1099 response->flags = fido_assert_flags(assert, 0);
1100 response->counter = fido_assert_sigcount(assert, 0);
1101 if (pack_sig(alg, assert, response) != 0) {
1102 skdebug(__func__, "pack_sig failed");
1103 goto out;
1104 }
1105 *sign_response = response;
1106 response = NULL;
1107 ret = 0;
1108 out:
1109 free(device);
1110 if (response != NULL) {
1111 free(response->sig_r);
1112 free(response->sig_s);
1113 free(response);
1114 }
1115 sk_close(sk);
1116 fido_assert_free(&assert);
1117 return ret;
1118 }
1119
1120 static int
read_rks(struct sk_usbhid * sk,const char * pin,struct sk_resident_key *** rksp,size_t * nrksp)1121 read_rks(struct sk_usbhid *sk, const char *pin,
1122 struct sk_resident_key ***rksp, size_t *nrksp)
1123 {
1124 int ret = SSH_SK_ERR_GENERAL, r = -1, internal_uv;
1125 fido_credman_metadata_t *metadata = NULL;
1126 fido_credman_rp_t *rp = NULL;
1127 fido_credman_rk_t *rk = NULL;
1128 size_t i, j, nrp, nrk, user_id_len;
1129 const fido_cred_t *cred;
1130 const char *rp_id, *rp_name, *user_name;
1131 struct sk_resident_key *srk = NULL, **tmp;
1132 const u_char *user_id;
1133
1134 if (pin == NULL) {
1135 skdebug(__func__, "no PIN specified");
1136 ret = SSH_SK_ERR_PIN_REQUIRED;
1137 goto out;
1138 }
1139 if ((metadata = fido_credman_metadata_new()) == NULL) {
1140 skdebug(__func__, "alloc failed");
1141 goto out;
1142 }
1143 if (check_sk_options(sk->dev, "uv", &internal_uv) != 0) {
1144 skdebug(__func__, "check_sk_options failed");
1145 goto out;
1146 }
1147
1148 if ((r = fido_credman_get_dev_metadata(sk->dev, metadata, pin)) != 0) {
1149 if (r == FIDO_ERR_INVALID_COMMAND) {
1150 skdebug(__func__, "device %s does not support "
1151 "resident keys", sk->path);
1152 ret = 0;
1153 goto out;
1154 }
1155 skdebug(__func__, "get metadata for %s failed: %s",
1156 sk->path, fido_strerr(r));
1157 ret = fidoerr_to_skerr(r);
1158 goto out;
1159 }
1160 skdebug(__func__, "existing %llu, remaining %llu",
1161 (unsigned long long)fido_credman_rk_existing(metadata),
1162 (unsigned long long)fido_credman_rk_remaining(metadata));
1163 if ((rp = fido_credman_rp_new()) == NULL) {
1164 skdebug(__func__, "alloc rp failed");
1165 goto out;
1166 }
1167 if ((r = fido_credman_get_dev_rp(sk->dev, rp, pin)) != 0) {
1168 skdebug(__func__, "get RPs for %s failed: %s",
1169 sk->path, fido_strerr(r));
1170 goto out;
1171 }
1172 nrp = fido_credman_rp_count(rp);
1173 skdebug(__func__, "Device %s has resident keys for %zu RPs",
1174 sk->path, nrp);
1175
1176 /* Iterate over RP IDs that have resident keys */
1177 for (i = 0; i < nrp; i++) {
1178 rp_id = fido_credman_rp_id(rp, i);
1179 rp_name = fido_credman_rp_name(rp, i);
1180 skdebug(__func__, "rp %zu: name=\"%s\" id=\"%s\" hashlen=%zu",
1181 i, rp_name == NULL ? "(none)" : rp_name,
1182 rp_id == NULL ? "(none)" : rp_id,
1183 fido_credman_rp_id_hash_len(rp, i));
1184
1185 /* Skip non-SSH RP IDs */
1186 if (rp_id == NULL ||
1187 strncasecmp(fido_credman_rp_id(rp, i), "ssh:", 4) != 0)
1188 continue;
1189
1190 fido_credman_rk_free(&rk);
1191 if ((rk = fido_credman_rk_new()) == NULL) {
1192 skdebug(__func__, "alloc rk failed");
1193 goto out;
1194 }
1195 if ((r = fido_credman_get_dev_rk(sk->dev,
1196 fido_credman_rp_id(rp, i), rk, pin)) != 0) {
1197 skdebug(__func__, "get RKs for %s slot %zu failed: %s",
1198 sk->path, i, fido_strerr(r));
1199 goto out;
1200 }
1201 nrk = fido_credman_rk_count(rk);
1202 skdebug(__func__, "RP \"%s\" has %zu resident keys",
1203 fido_credman_rp_id(rp, i), nrk);
1204
1205 /* Iterate over resident keys for this RP ID */
1206 for (j = 0; j < nrk; j++) {
1207 if ((cred = fido_credman_rk(rk, j)) == NULL) {
1208 skdebug(__func__, "no RK in slot %zu", j);
1209 continue;
1210 }
1211 if ((user_name = fido_cred_user_name(cred)) == NULL)
1212 user_name = "";
1213 user_id = fido_cred_user_id_ptr(cred);
1214 user_id_len = fido_cred_user_id_len(cred);
1215 skdebug(__func__, "Device %s RP \"%s\" user \"%s\" "
1216 "uidlen %zu slot %zu: type %d flags 0x%02x "
1217 "prot 0x%02x", sk->path, rp_id, user_name,
1218 user_id_len, j, fido_cred_type(cred),
1219 fido_cred_flags(cred), fido_cred_prot(cred));
1220
1221 /* build response entry */
1222 if ((srk = calloc(1, sizeof(*srk))) == NULL ||
1223 (srk->key.key_handle = calloc(1,
1224 fido_cred_id_len(cred))) == NULL ||
1225 (srk->application = strdup(rp_id)) == NULL ||
1226 (user_id_len > 0 &&
1227 (srk->user_id = calloc(1, user_id_len)) == NULL)) {
1228 skdebug(__func__, "alloc sk_resident_key");
1229 goto out;
1230 }
1231
1232 srk->key.key_handle_len = fido_cred_id_len(cred);
1233 memcpy(srk->key.key_handle, fido_cred_id_ptr(cred),
1234 srk->key.key_handle_len);
1235 srk->user_id_len = user_id_len;
1236 if (srk->user_id_len != 0)
1237 memcpy(srk->user_id, user_id, srk->user_id_len);
1238
1239 switch (fido_cred_type(cred)) {
1240 case COSE_ES256:
1241 srk->alg = SSH_SK_ECDSA;
1242 break;
1243 case COSE_EDDSA:
1244 srk->alg = SSH_SK_ED25519;
1245 break;
1246 default:
1247 skdebug(__func__, "unsupported key type %d",
1248 fido_cred_type(cred));
1249 goto out; /* XXX free rk and continue */
1250 }
1251
1252 if (fido_cred_prot(cred) == FIDO_CRED_PROT_UV_REQUIRED
1253 && internal_uv == -1)
1254 srk->flags |= SSH_SK_USER_VERIFICATION_REQD;
1255
1256 if ((r = pack_public_key(srk->alg, cred,
1257 &srk->key)) != 0) {
1258 skdebug(__func__, "pack public key failed");
1259 goto out;
1260 }
1261 /* append */
1262 if ((tmp = recallocarray(*rksp, *nrksp, (*nrksp) + 1,
1263 sizeof(**rksp))) == NULL) {
1264 skdebug(__func__, "alloc rksp");
1265 goto out;
1266 }
1267 *rksp = tmp;
1268 (*rksp)[(*nrksp)++] = srk;
1269 srk = NULL;
1270 }
1271 }
1272 /* Success */
1273 ret = 0;
1274 out:
1275 if (srk != NULL) {
1276 free(srk->application);
1277 freezero(srk->key.public_key, srk->key.public_key_len);
1278 freezero(srk->key.key_handle, srk->key.key_handle_len);
1279 freezero(srk->user_id, srk->user_id_len);
1280 freezero(srk, sizeof(*srk));
1281 }
1282 fido_credman_rp_free(&rp);
1283 fido_credman_rk_free(&rk);
1284 fido_credman_metadata_free(&metadata);
1285 return ret;
1286 }
1287
1288 int
sk_load_resident_keys(const char * pin,struct sk_option ** options,struct sk_resident_key *** rksp,size_t * nrksp)1289 sk_load_resident_keys(const char *pin, struct sk_option **options,
1290 struct sk_resident_key ***rksp, size_t *nrksp)
1291 {
1292 int ret = SSH_SK_ERR_GENERAL, r = -1;
1293 size_t i, nrks = 0;
1294 struct sk_resident_key **rks = NULL;
1295 struct sk_usbhid *sk = NULL;
1296 char *device = NULL;
1297
1298 *rksp = NULL;
1299 *nrksp = 0;
1300
1301 fido_init(SSH_FIDO_INIT_ARG);
1302
1303 if (check_sign_load_resident_options(options, &device) != 0)
1304 goto out; /* error already logged */
1305 if (device != NULL)
1306 sk = sk_open(device);
1307 else
1308 sk = sk_probe(NULL, NULL, 0, 1);
1309 if (sk == NULL) {
1310 ret = SSH_SK_ERR_DEVICE_NOT_FOUND;
1311 skdebug(__func__, "failed to find sk");
1312 goto out;
1313 }
1314 skdebug(__func__, "trying %s", sk->path);
1315 if ((r = read_rks(sk, pin, &rks, &nrks)) != 0) {
1316 skdebug(__func__, "read_rks failed for %s", sk->path);
1317 ret = r;
1318 goto out;
1319 }
1320 /* success, unless we have no keys but a specific error */
1321 if (nrks > 0 || ret == SSH_SK_ERR_GENERAL)
1322 ret = 0;
1323 *rksp = rks;
1324 *nrksp = nrks;
1325 rks = NULL;
1326 nrks = 0;
1327 out:
1328 sk_close(sk);
1329 for (i = 0; i < nrks; i++) {
1330 free(rks[i]->application);
1331 freezero(rks[i]->key.public_key, rks[i]->key.public_key_len);
1332 freezero(rks[i]->key.key_handle, rks[i]->key.key_handle_len);
1333 freezero(rks[i]->user_id, rks[i]->user_id_len);
1334 freezero(rks[i], sizeof(*rks[i]));
1335 }
1336 free(device);
1337 free(rks);
1338 return ret;
1339 }
1340
1341