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