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