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