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