xref: /openssh-portable/sk-usbhid.c (revision 1e70dc32)
1 /*
2  * Copyright (c) 2019 Markus Friedl
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include "includes.h"
18 
19 #ifdef ENABLE_SK_INTERNAL
20 
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <stddef.h>
26 #include <stdarg.h>
27 #ifdef HAVE_SHA2_H
28 #include <sha2.h>
29 #endif
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 /*
47  * If building as part of OpenSSH, then rename exported functions.
48  * This must be done before including sk-api.h.
49  */
50 # define sk_api_version		ssh_sk_api_version
51 # define sk_enroll		ssh_sk_enroll
52 # define sk_sign		ssh_sk_sign
53 # define sk_load_resident_keys	ssh_sk_load_resident_keys
54 #endif /* !SK_STANDALONE */
55 
56 #include "sk-api.h"
57 
58 /* #define SK_DEBUG 1 */
59 
60 #ifdef SK_DEBUG
61 #define SSH_FIDO_INIT_ARG	FIDO_DEBUG
62 #else
63 #define SSH_FIDO_INIT_ARG	0
64 #endif
65 
66 #define MAX_FIDO_DEVICES	256
67 
68 /* Compatibility with OpenSSH 1.0.x */
69 #if (OPENSSL_VERSION_NUMBER < 0x10100000L)
70 #define ECDSA_SIG_get0(sig, pr, ps) \
71 	do { \
72 		(*pr) = sig->r; \
73 		(*ps) = sig->s; \
74 	} while (0)
75 #endif
76 
77 /* Return the version of the middleware API */
78 uint32_t sk_api_version(void);
79 
80 /* Enroll a U2F key (private key generation) */
81 int sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
82     const char *application, uint8_t flags, const char *pin,
83     struct sk_option **options, struct sk_enroll_response **enroll_response);
84 
85 /* Sign a challenge */
86 int sk_sign(uint32_t alg, const uint8_t *message, size_t message_len,
87     const char *application, const uint8_t *key_handle, size_t key_handle_len,
88     uint8_t flags, const char *pin, struct sk_option **options,
89     struct sk_sign_response **sign_response);
90 
91 /* Load resident keys */
92 int sk_load_resident_keys(const char *pin, struct sk_option **options,
93     struct sk_resident_key ***rks, size_t *nrks);
94 
95 static void skdebug(const char *func, const char *fmt, ...)
96     __attribute__((__format__ (printf, 2, 3)));
97 
98 static void
99 skdebug(const char *func, const char *fmt, ...)
100 {
101 #if !defined(SK_STANDALONE)
102 	char *msg;
103 	va_list ap;
104 
105 	va_start(ap, fmt);
106 	xvasprintf(&msg, fmt, ap);
107 	va_end(ap);
108 	debug("%s: %s", func, msg);
109 	free(msg);
110 #elif defined(SK_DEBUG)
111 	va_list ap;
112 
113 	va_start(ap, fmt);
114 	fprintf(stderr, "%s: ", func);
115 	vfprintf(stderr, fmt, ap);
116 	fputc('\n', stderr);
117 	va_end(ap);
118 #else
119 	(void)func; /* XXX */
120 	(void)fmt; /* XXX */
121 #endif
122 }
123 
124 uint32_t
125 sk_api_version(void)
126 {
127 	return SSH_SK_VERSION_MAJOR;
128 }
129 
130 /* Select the first identified FIDO device attached to the system */
131 static char *
132 pick_first_device(void)
133 {
134 	char *ret = NULL;
135 	fido_dev_info_t *devlist = NULL;
136 	size_t olen = 0;
137 	int r;
138 	const fido_dev_info_t *di;
139 
140 	if ((devlist = fido_dev_info_new(1)) == NULL) {
141 		skdebug(__func__, "fido_dev_info_new failed");
142 		goto out;
143 	}
144 	if ((r = fido_dev_info_manifest(devlist, 1, &olen)) != FIDO_OK) {
145 		skdebug(__func__, "fido_dev_info_manifest failed: %s",
146 		    fido_strerr(r));
147 		goto out;
148 	}
149 	if (olen != 1) {
150 		skdebug(__func__, "fido_dev_info_manifest bad len %zu", olen);
151 		goto out;
152 	}
153 	di = fido_dev_info_ptr(devlist, 0);
154 	if ((ret = strdup(fido_dev_info_path(di))) == NULL) {
155 		skdebug(__func__, "fido_dev_info_path failed");
156 		goto out;
157 	}
158  out:
159 	fido_dev_info_free(&devlist, 1);
160 	return ret;
161 }
162 
163 /* Check if the specified key handle exists on a given device. */
164 static int
165 try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len,
166     const char *application, const uint8_t *key_handle, size_t key_handle_len)
167 {
168 	fido_assert_t *assert = NULL;
169 	int r = FIDO_ERR_INTERNAL;
170 
171 	if ((assert = fido_assert_new()) == NULL) {
172 		skdebug(__func__, "fido_assert_new failed");
173 		goto out;
174 	}
175 	if ((r = fido_assert_set_clientdata_hash(assert, message,
176 	    message_len)) != FIDO_OK) {
177 		skdebug(__func__, "fido_assert_set_clientdata_hash: %s",
178 		    fido_strerr(r));
179 		goto out;
180 	}
181 	if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK) {
182 		skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r));
183 		goto out;
184 	}
185 	if ((r = fido_assert_allow_cred(assert, key_handle,
186 	    key_handle_len)) != FIDO_OK) {
187 		skdebug(__func__, "fido_assert_allow_cred: %s", fido_strerr(r));
188 		goto out;
189 	}
190 	if ((r = fido_assert_set_up(assert, FIDO_OPT_FALSE)) != FIDO_OK) {
191 		skdebug(__func__, "fido_assert_up: %s", fido_strerr(r));
192 		goto out;
193 	}
194 	r = fido_dev_get_assert(dev, assert, NULL);
195 	skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
196 	if (r == FIDO_ERR_USER_PRESENCE_REQUIRED) {
197 		/* U2F tokens may return this */
198 		r = FIDO_OK;
199 	}
200  out:
201 	fido_assert_free(&assert);
202 
203 	return r != FIDO_OK ? -1 : 0;
204 }
205 
206 /* Iterate over configured devices looking for a specific key handle */
207 static fido_dev_t *
208 find_device(const char *path, const uint8_t *message, size_t message_len,
209     const char *application, const uint8_t *key_handle, size_t key_handle_len)
210 {
211 	fido_dev_info_t *devlist = NULL;
212 	fido_dev_t *dev = NULL;
213 	size_t devlist_len = 0, i;
214 	int r;
215 
216 	if (path != NULL) {
217 		if ((dev = fido_dev_new()) == NULL) {
218 			skdebug(__func__, "fido_dev_new failed");
219 			return NULL;
220 		}
221 		if ((r = fido_dev_open(dev, path)) != FIDO_OK) {
222 			skdebug(__func__, "fido_dev_open failed");
223 			fido_dev_free(&dev);
224 			return NULL;
225 		}
226 		return dev;
227 	}
228 
229 	if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) {
230 		skdebug(__func__, "fido_dev_info_new failed");
231 		goto out;
232 	}
233 	if ((r = fido_dev_info_manifest(devlist, MAX_FIDO_DEVICES,
234 	    &devlist_len)) != FIDO_OK) {
235 		skdebug(__func__, "fido_dev_info_manifest: %s", fido_strerr(r));
236 		goto out;
237 	}
238 
239 	skdebug(__func__, "found %zu device(s)", devlist_len);
240 
241 	for (i = 0; i < devlist_len; i++) {
242 		const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i);
243 
244 		if (di == NULL) {
245 			skdebug(__func__, "fido_dev_info_ptr %zu failed", i);
246 			continue;
247 		}
248 		if ((path = fido_dev_info_path(di)) == NULL) {
249 			skdebug(__func__, "fido_dev_info_path %zu failed", i);
250 			continue;
251 		}
252 		skdebug(__func__, "trying device %zu: %s", i, path);
253 		if ((dev = fido_dev_new()) == NULL) {
254 			skdebug(__func__, "fido_dev_new failed");
255 			continue;
256 		}
257 		if ((r = fido_dev_open(dev, path)) != FIDO_OK) {
258 			skdebug(__func__, "fido_dev_open failed");
259 			fido_dev_free(&dev);
260 			continue;
261 		}
262 		if (try_device(dev, message, message_len, application,
263 		    key_handle, key_handle_len) == 0) {
264 			skdebug(__func__, "found key");
265 			break;
266 		}
267 		fido_dev_close(dev);
268 		fido_dev_free(&dev);
269 	}
270 
271  out:
272 	if (devlist != NULL)
273 		fido_dev_info_free(&devlist, MAX_FIDO_DEVICES);
274 
275 	return dev;
276 }
277 
278 #ifdef WITH_OPENSSL
279 /*
280  * The key returned via fido_cred_pubkey_ptr() is in affine coordinates,
281  * but the API expects a SEC1 octet string.
282  */
283 static int
284 pack_public_key_ecdsa(const fido_cred_t *cred,
285     struct sk_enroll_response *response)
286 {
287 	const uint8_t *ptr;
288 	BIGNUM *x = NULL, *y = NULL;
289 	EC_POINT *q = NULL;
290 	EC_GROUP *g = NULL;
291 	int ret = -1;
292 
293 	response->public_key = NULL;
294 	response->public_key_len = 0;
295 
296 	if ((x = BN_new()) == NULL ||
297 	    (y = BN_new()) == NULL ||
298 	    (g = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)) == NULL ||
299 	    (q = EC_POINT_new(g)) == NULL) {
300 		skdebug(__func__, "libcrypto setup failed");
301 		goto out;
302 	}
303 	if ((ptr = fido_cred_pubkey_ptr(cred)) == NULL) {
304 		skdebug(__func__, "fido_cred_pubkey_ptr failed");
305 		goto out;
306 	}
307 	if (fido_cred_pubkey_len(cred) != 64) {
308 		skdebug(__func__, "bad fido_cred_pubkey_len %zu",
309 		    fido_cred_pubkey_len(cred));
310 		goto out;
311 	}
312 
313 	if (BN_bin2bn(ptr, 32, x) == NULL ||
314 	    BN_bin2bn(ptr + 32, 32, y) == NULL) {
315 		skdebug(__func__, "BN_bin2bn failed");
316 		goto out;
317 	}
318 	if (EC_POINT_set_affine_coordinates_GFp(g, q, x, y, NULL) != 1) {
319 		skdebug(__func__, "EC_POINT_set_affine_coordinates_GFp failed");
320 		goto out;
321 	}
322 	response->public_key_len = EC_POINT_point2oct(g, q,
323 	    POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
324 	if (response->public_key_len == 0 || response->public_key_len > 2048) {
325 		skdebug(__func__, "bad pubkey length %zu",
326 		    response->public_key_len);
327 		goto out;
328 	}
329 	if ((response->public_key = malloc(response->public_key_len)) == NULL) {
330 		skdebug(__func__, "malloc pubkey failed");
331 		goto out;
332 	}
333 	if (EC_POINT_point2oct(g, q, POINT_CONVERSION_UNCOMPRESSED,
334 	    response->public_key, response->public_key_len, NULL) == 0) {
335 		skdebug(__func__, "EC_POINT_point2oct failed");
336 		goto out;
337 	}
338 	/* success */
339 	ret = 0;
340  out:
341 	if (ret != 0 && response->public_key != NULL) {
342 		memset(response->public_key, 0, response->public_key_len);
343 		free(response->public_key);
344 		response->public_key = NULL;
345 	}
346 	EC_POINT_free(q);
347 	EC_GROUP_free(g);
348 	BN_clear_free(x);
349 	BN_clear_free(y);
350 	return ret;
351 }
352 #endif /* WITH_OPENSSL */
353 
354 static int
355 pack_public_key_ed25519(const fido_cred_t *cred,
356     struct sk_enroll_response *response)
357 {
358 	const uint8_t *ptr;
359 	size_t len;
360 	int ret = -1;
361 
362 	response->public_key = NULL;
363 	response->public_key_len = 0;
364 
365 	if ((len = fido_cred_pubkey_len(cred)) != 32) {
366 		skdebug(__func__, "bad fido_cred_pubkey_len len %zu", len);
367 		goto out;
368 	}
369 	if ((ptr = fido_cred_pubkey_ptr(cred)) == NULL) {
370 		skdebug(__func__, "fido_cred_pubkey_ptr failed");
371 		goto out;
372 	}
373 	response->public_key_len = len;
374 	if ((response->public_key = malloc(response->public_key_len)) == NULL) {
375 		skdebug(__func__, "malloc pubkey failed");
376 		goto out;
377 	}
378 	memcpy(response->public_key, ptr, len);
379 	ret = 0;
380  out:
381 	if (ret != 0)
382 		free(response->public_key);
383 	return ret;
384 }
385 
386 static int
387 pack_public_key(uint32_t alg, const fido_cred_t *cred,
388     struct sk_enroll_response *response)
389 {
390 	switch(alg) {
391 #ifdef WITH_OPENSSL
392 	case SSH_SK_ECDSA:
393 		return pack_public_key_ecdsa(cred, response);
394 #endif /* WITH_OPENSSL */
395 	case SSH_SK_ED25519:
396 		return pack_public_key_ed25519(cred, response);
397 	default:
398 		return -1;
399 	}
400 }
401 
402 static int
403 fidoerr_to_skerr(int fidoerr)
404 {
405 	switch (fidoerr) {
406 	case FIDO_ERR_UNSUPPORTED_OPTION:
407 	case FIDO_ERR_UNSUPPORTED_ALGORITHM:
408 		return SSH_SK_ERR_UNSUPPORTED;
409 	case FIDO_ERR_PIN_REQUIRED:
410 	case FIDO_ERR_PIN_INVALID:
411 		return SSH_SK_ERR_PIN_REQUIRED;
412 	default:
413 		return -1;
414 	}
415 }
416 
417 static int
418 check_enroll_options(struct sk_option **options, char **devicep,
419     uint8_t *user_id, size_t user_id_len)
420 {
421 	size_t i;
422 
423 	if (options == NULL)
424 		return 0;
425 	for (i = 0; options[i] != NULL; i++) {
426 		if (strcmp(options[i]->name, "device") == 0) {
427 			if ((*devicep = strdup(options[i]->value)) == NULL) {
428 				skdebug(__func__, "strdup device failed");
429 				return -1;
430 			}
431 			skdebug(__func__, "requested device %s", *devicep);
432 		} else if (strcmp(options[i]->name, "user") == 0) {
433 			if (strlcpy(user_id, options[i]->value, user_id_len) >=
434 			    user_id_len) {
435 				skdebug(__func__, "user too long");
436 				return -1;
437 			}
438 			skdebug(__func__, "requested user %s",
439 			    (char *)user_id);
440 		} else {
441 			skdebug(__func__, "requested unsupported option %s",
442 			    options[i]->name);
443 			if (options[i]->required) {
444 				skdebug(__func__, "unknown required option");
445 				return -1;
446 			}
447 		}
448 	}
449 	return 0;
450 }
451 
452 int
453 sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
454     const char *application, uint8_t flags, const char *pin,
455     struct sk_option **options, struct sk_enroll_response **enroll_response)
456 {
457 	fido_cred_t *cred = NULL;
458 	fido_dev_t *dev = NULL;
459 	const uint8_t *ptr;
460 	uint8_t user_id[32];
461 	struct sk_enroll_response *response = NULL;
462 	size_t len;
463 	int cose_alg;
464 	int ret = SSH_SK_ERR_GENERAL;
465 	int r;
466 	char *device = NULL;
467 
468 	fido_init(SSH_FIDO_INIT_ARG);
469 
470 	if (enroll_response == NULL) {
471 		skdebug(__func__, "enroll_response == NULL");
472 		goto out;
473 	}
474 	memset(user_id, 0, sizeof(user_id));
475 	if (check_enroll_options(options, &device,
476 	    user_id, sizeof(user_id)) != 0)
477 		goto out; /* error already logged */
478 
479 	*enroll_response = NULL;
480 	switch(alg) {
481 #ifdef WITH_OPENSSL
482 	case SSH_SK_ECDSA:
483 		cose_alg = COSE_ES256;
484 		break;
485 #endif /* WITH_OPENSSL */
486 	case SSH_SK_ED25519:
487 		cose_alg = COSE_EDDSA;
488 		break;
489 	default:
490 		skdebug(__func__, "unsupported key type %d", alg);
491 		goto out;
492 	}
493 	if (device == NULL && (device = pick_first_device()) == NULL) {
494 		ret = SSH_SK_ERR_DEVICE_NOT_FOUND;
495 		skdebug(__func__, "pick_first_device failed");
496 		goto out;
497 	}
498 	skdebug(__func__, "using device %s", device);
499 	if ((cred = fido_cred_new()) == NULL) {
500 		skdebug(__func__, "fido_cred_new failed");
501 		goto out;
502 	}
503 	if ((r = fido_cred_set_type(cred, cose_alg)) != FIDO_OK) {
504 		skdebug(__func__, "fido_cred_set_type: %s", fido_strerr(r));
505 		goto out;
506 	}
507 	if ((r = fido_cred_set_clientdata_hash(cred, challenge,
508 	    challenge_len)) != FIDO_OK) {
509 		skdebug(__func__, "fido_cred_set_clientdata_hash: %s",
510 		    fido_strerr(r));
511 		goto out;
512 	}
513 	if ((r = fido_cred_set_rk(cred, (flags & SSH_SK_RESIDENT_KEY) != 0 ?
514 	    FIDO_OPT_TRUE : FIDO_OPT_OMIT)) != FIDO_OK) {
515 		skdebug(__func__, "fido_cred_set_rk: %s", fido_strerr(r));
516 		goto out;
517 	}
518 	if ((r = fido_cred_set_user(cred, user_id, sizeof(user_id),
519 	    "openssh", "openssh", NULL)) != FIDO_OK) {
520 		skdebug(__func__, "fido_cred_set_user: %s", fido_strerr(r));
521 		goto out;
522 	}
523 	if ((r = fido_cred_set_rp(cred, application, NULL)) != FIDO_OK) {
524 		skdebug(__func__, "fido_cred_set_rp: %s", fido_strerr(r));
525 		goto out;
526 	}
527 	if ((dev = fido_dev_new()) == NULL) {
528 		skdebug(__func__, "fido_dev_new failed");
529 		goto out;
530 	}
531 	if ((r = fido_dev_open(dev, device)) != FIDO_OK) {
532 		skdebug(__func__, "fido_dev_open: %s", fido_strerr(r));
533 		goto out;
534 	}
535 	if ((r = fido_dev_make_cred(dev, cred, pin)) != FIDO_OK) {
536 		skdebug(__func__, "fido_dev_make_cred: %s", fido_strerr(r));
537 		ret = fidoerr_to_skerr(r);
538 		goto out;
539 	}
540 	if (fido_cred_x5c_ptr(cred) != NULL) {
541 		if ((r = fido_cred_verify(cred)) != FIDO_OK) {
542 			skdebug(__func__, "fido_cred_verify: %s",
543 			    fido_strerr(r));
544 			goto out;
545 		}
546 	} else {
547 		skdebug(__func__, "self-attested credential");
548 		if ((r = fido_cred_verify_self(cred)) != FIDO_OK) {
549 			skdebug(__func__, "fido_cred_verify_self: %s",
550 			    fido_strerr(r));
551 			goto out;
552 		}
553 	}
554 	if ((response = calloc(1, sizeof(*response))) == NULL) {
555 		skdebug(__func__, "calloc response failed");
556 		goto out;
557 	}
558 	if (pack_public_key(alg, cred, response) != 0) {
559 		skdebug(__func__, "pack_public_key failed");
560 		goto out;
561 	}
562 	if ((ptr = fido_cred_id_ptr(cred)) != NULL) {
563 		len = fido_cred_id_len(cred);
564 		if ((response->key_handle = calloc(1, len)) == NULL) {
565 			skdebug(__func__, "calloc key handle failed");
566 			goto out;
567 		}
568 		memcpy(response->key_handle, ptr, len);
569 		response->key_handle_len = len;
570 	}
571 	if ((ptr = fido_cred_sig_ptr(cred)) != NULL) {
572 		len = fido_cred_sig_len(cred);
573 		if ((response->signature = calloc(1, len)) == NULL) {
574 			skdebug(__func__, "calloc signature failed");
575 			goto out;
576 		}
577 		memcpy(response->signature, ptr, len);
578 		response->signature_len = len;
579 	}
580 	if ((ptr = fido_cred_x5c_ptr(cred)) != NULL) {
581 		len = fido_cred_x5c_len(cred);
582 		debug3("%s: attestation cert len=%zu", __func__, len);
583 		if ((response->attestation_cert = calloc(1, len)) == NULL) {
584 			skdebug(__func__, "calloc attestation cert failed");
585 			goto out;
586 		}
587 		memcpy(response->attestation_cert, ptr, len);
588 		response->attestation_cert_len = len;
589 	}
590 	*enroll_response = response;
591 	response = NULL;
592 	ret = 0;
593  out:
594 	free(device);
595 	if (response != NULL) {
596 		free(response->public_key);
597 		free(response->key_handle);
598 		free(response->signature);
599 		free(response->attestation_cert);
600 		free(response);
601 	}
602 	if (dev != NULL) {
603 		fido_dev_close(dev);
604 		fido_dev_free(&dev);
605 	}
606 	if (cred != NULL) {
607 		fido_cred_free(&cred);
608 	}
609 	return ret;
610 }
611 
612 #ifdef WITH_OPENSSL
613 static int
614 pack_sig_ecdsa(fido_assert_t *assert, struct sk_sign_response *response)
615 {
616 	ECDSA_SIG *sig = NULL;
617 	const BIGNUM *sig_r, *sig_s;
618 	const unsigned char *cp;
619 	size_t sig_len;
620 	int ret = -1;
621 
622 	cp = fido_assert_sig_ptr(assert, 0);
623 	sig_len = fido_assert_sig_len(assert, 0);
624 	if ((sig = d2i_ECDSA_SIG(NULL, &cp, sig_len)) == NULL) {
625 		skdebug(__func__, "d2i_ECDSA_SIG failed");
626 		goto out;
627 	}
628 	ECDSA_SIG_get0(sig, &sig_r, &sig_s);
629 	response->sig_r_len = BN_num_bytes(sig_r);
630 	response->sig_s_len = BN_num_bytes(sig_s);
631 	if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL ||
632 	    (response->sig_s = calloc(1, response->sig_s_len)) == NULL) {
633 		skdebug(__func__, "calloc signature failed");
634 		goto out;
635 	}
636 	BN_bn2bin(sig_r, response->sig_r);
637 	BN_bn2bin(sig_s, response->sig_s);
638 	ret = 0;
639  out:
640 	ECDSA_SIG_free(sig);
641 	if (ret != 0) {
642 		free(response->sig_r);
643 		free(response->sig_s);
644 		response->sig_r = NULL;
645 		response->sig_s = NULL;
646 	}
647 	return ret;
648 }
649 #endif /* WITH_OPENSSL */
650 
651 static int
652 pack_sig_ed25519(fido_assert_t *assert, struct sk_sign_response *response)
653 {
654 	const unsigned char *ptr;
655 	size_t len;
656 	int ret = -1;
657 
658 	ptr = fido_assert_sig_ptr(assert, 0);
659 	len = fido_assert_sig_len(assert, 0);
660 	if (len != 64) {
661 		skdebug(__func__, "bad length %zu", len);
662 		goto out;
663 	}
664 	response->sig_r_len = len;
665 	if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL) {
666 		skdebug(__func__, "calloc signature failed");
667 		goto out;
668 	}
669 	memcpy(response->sig_r, ptr, len);
670 	ret = 0;
671  out:
672 	if (ret != 0) {
673 		free(response->sig_r);
674 		response->sig_r = NULL;
675 	}
676 	return ret;
677 }
678 
679 static int
680 pack_sig(uint32_t  alg, fido_assert_t *assert,
681     struct sk_sign_response *response)
682 {
683 	switch(alg) {
684 #ifdef WITH_OPENSSL
685 	case SSH_SK_ECDSA:
686 		return pack_sig_ecdsa(assert, response);
687 #endif /* WITH_OPENSSL */
688 	case SSH_SK_ED25519:
689 		return pack_sig_ed25519(assert, response);
690 	default:
691 		return -1;
692 	}
693 }
694 
695 /* Checks sk_options for sk_sign() and sk_load_resident_keys() */
696 static int
697 check_sign_load_resident_options(struct sk_option **options, char **devicep)
698 {
699 	size_t i;
700 
701 	if (options == NULL)
702 		return 0;
703 	for (i = 0; options[i] != NULL; i++) {
704 		if (strcmp(options[i]->name, "device") == 0) {
705 			if ((*devicep = strdup(options[i]->value)) == NULL) {
706 				skdebug(__func__, "strdup device failed");
707 				return -1;
708 			}
709 			skdebug(__func__, "requested device %s", *devicep);
710 		} else {
711 			skdebug(__func__, "requested unsupported option %s",
712 			    options[i]->name);
713 			if (options[i]->required) {
714 				skdebug(__func__, "unknown required option");
715 				return -1;
716 			}
717 		}
718 	}
719 	return 0;
720 }
721 
722 /* Calculate SHA256(m) */
723 static int
724 sha256_mem(const void *m, size_t mlen, u_char *d, size_t dlen)
725 {
726 #ifdef WITH_OPENSSL
727 	u_int mdlen;
728 #endif
729 
730 	if (dlen != 32)
731 		return -1;
732 #ifdef WITH_OPENSSL
733 	mdlen = dlen;
734 	if (!EVP_Digest(m, mlen, d, &mdlen, EVP_sha256(), NULL))
735 		return -1;
736 #else
737 	SHA256Data(m, mlen, d);
738 #endif
739 	return 0;
740 }
741 
742 int
743 sk_sign(uint32_t alg, const uint8_t *data, size_t datalen,
744     const char *application,
745     const uint8_t *key_handle, size_t key_handle_len,
746     uint8_t flags, const char *pin, struct sk_option **options,
747     struct sk_sign_response **sign_response)
748 {
749 	fido_assert_t *assert = NULL;
750 	char *device = NULL;
751 	fido_dev_t *dev = NULL;
752 	struct sk_sign_response *response = NULL;
753 	uint8_t message[32];
754 	int ret = SSH_SK_ERR_GENERAL;
755 	int r;
756 
757 	fido_init(SSH_FIDO_INIT_ARG);
758 
759 	if (sign_response == NULL) {
760 		skdebug(__func__, "sign_response == NULL");
761 		goto out;
762 	}
763 	*sign_response = NULL;
764 	if (check_sign_load_resident_options(options, &device) != 0)
765 		goto out; /* error already logged */
766 	/* hash data to be signed before it goes to the security key */
767 	if ((r = sha256_mem(data, datalen, message, sizeof(message))) != 0) {
768 		skdebug(__func__, "hash message failed");
769 		goto out;
770 	}
771 	if ((dev = find_device(device, message, sizeof(message),
772 	    application, key_handle, key_handle_len)) == NULL) {
773 		skdebug(__func__, "couldn't find device for key handle");
774 		goto out;
775 	}
776 	if ((assert = fido_assert_new()) == NULL) {
777 		skdebug(__func__, "fido_assert_new failed");
778 		goto out;
779 	}
780 	if ((r = fido_assert_set_clientdata_hash(assert, message,
781 	    sizeof(message))) != FIDO_OK) {
782 		skdebug(__func__, "fido_assert_set_clientdata_hash: %s",
783 		    fido_strerr(r));
784 		goto out;
785 	}
786 	if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK) {
787 		skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r));
788 		goto out;
789 	}
790 	if ((r = fido_assert_allow_cred(assert, key_handle,
791 	    key_handle_len)) != FIDO_OK) {
792 		skdebug(__func__, "fido_assert_allow_cred: %s", fido_strerr(r));
793 		goto out;
794 	}
795 	if ((r = fido_assert_set_up(assert,
796 	    (flags & SSH_SK_USER_PRESENCE_REQD) ?
797 	    FIDO_OPT_TRUE : FIDO_OPT_FALSE)) != FIDO_OK) {
798 		skdebug(__func__, "fido_assert_set_up: %s", fido_strerr(r));
799 		goto out;
800 	}
801 	if ((r = fido_dev_get_assert(dev, assert, NULL)) != FIDO_OK) {
802 		skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
803 		goto out;
804 	}
805 	if ((response = calloc(1, sizeof(*response))) == NULL) {
806 		skdebug(__func__, "calloc response failed");
807 		goto out;
808 	}
809 	response->flags = fido_assert_flags(assert, 0);
810 	response->counter = fido_assert_sigcount(assert, 0);
811 	if (pack_sig(alg, assert, response) != 0) {
812 		skdebug(__func__, "pack_sig failed");
813 		goto out;
814 	}
815 	*sign_response = response;
816 	response = NULL;
817 	ret = 0;
818  out:
819 	explicit_bzero(message, sizeof(message));
820 	free(device);
821 	if (response != NULL) {
822 		free(response->sig_r);
823 		free(response->sig_s);
824 		free(response);
825 	}
826 	if (dev != NULL) {
827 		fido_dev_close(dev);
828 		fido_dev_free(&dev);
829 	}
830 	if (assert != NULL) {
831 		fido_assert_free(&assert);
832 	}
833 	return ret;
834 }
835 
836 static int
837 read_rks(const char *devpath, const char *pin,
838     struct sk_resident_key ***rksp, size_t *nrksp)
839 {
840 	int ret = SSH_SK_ERR_GENERAL, r = -1;
841 	fido_dev_t *dev = NULL;
842 	fido_credman_metadata_t *metadata = NULL;
843 	fido_credman_rp_t *rp = NULL;
844 	fido_credman_rk_t *rk = NULL;
845 	size_t i, j, nrp, nrk;
846 	const fido_cred_t *cred;
847 	struct sk_resident_key *srk = NULL, **tmp;
848 
849 	if ((dev = fido_dev_new()) == NULL) {
850 		skdebug(__func__, "fido_dev_new failed");
851 		return ret;
852 	}
853 	if ((r = fido_dev_open(dev, devpath)) != FIDO_OK) {
854 		skdebug(__func__, "fido_dev_open %s failed: %s",
855 		    devpath, fido_strerr(r));
856 		fido_dev_free(&dev);
857 		return ret;
858 	}
859 	if ((metadata = fido_credman_metadata_new()) == NULL) {
860 		skdebug(__func__, "alloc failed");
861 		goto out;
862 	}
863 
864 	if ((r = fido_credman_get_dev_metadata(dev, metadata, pin)) != 0) {
865 		if (r == FIDO_ERR_INVALID_COMMAND) {
866 			skdebug(__func__, "device %s does not support "
867 			    "resident keys", devpath);
868 			ret = 0;
869 			goto out;
870 		}
871 		skdebug(__func__, "get metadata for %s failed: %s",
872 		    devpath, fido_strerr(r));
873 		ret = fidoerr_to_skerr(r);
874 		goto out;
875 	}
876 	skdebug(__func__, "existing %llu, remaining %llu",
877 	    (unsigned long long)fido_credman_rk_existing(metadata),
878 	    (unsigned long long)fido_credman_rk_remaining(metadata));
879 	if ((rp = fido_credman_rp_new()) == NULL) {
880 		skdebug(__func__, "alloc rp failed");
881 		goto out;
882 	}
883 	if ((r = fido_credman_get_dev_rp(dev, rp, pin)) != 0) {
884 		skdebug(__func__, "get RPs for %s failed: %s",
885 		    devpath, fido_strerr(r));
886 		goto out;
887 	}
888 	nrp = fido_credman_rp_count(rp);
889 	skdebug(__func__, "Device %s has resident keys for %zu RPs",
890 	    devpath, nrp);
891 
892 	/* Iterate over RP IDs that have resident keys */
893 	for (i = 0; i < nrp; i++) {
894 		skdebug(__func__, "rp %zu: name=\"%s\" id=\"%s\" hashlen=%zu",
895 		    i, fido_credman_rp_name(rp, i), fido_credman_rp_id(rp, i),
896 		    fido_credman_rp_id_hash_len(rp, i));
897 
898 		/* Skip non-SSH RP IDs */
899 		if (strncasecmp(fido_credman_rp_id(rp, i), "ssh:", 4) != 0)
900 			continue;
901 
902 		fido_credman_rk_free(&rk);
903 		if ((rk = fido_credman_rk_new()) == NULL) {
904 			skdebug(__func__, "alloc rk failed");
905 			goto out;
906 		}
907 		if ((r = fido_credman_get_dev_rk(dev, fido_credman_rp_id(rp, i),
908 		    rk, pin)) != 0) {
909 			skdebug(__func__, "get RKs for %s slot %zu failed: %s",
910 			    devpath, i, fido_strerr(r));
911 			goto out;
912 		}
913 		nrk = fido_credman_rk_count(rk);
914 		skdebug(__func__, "RP \"%s\" has %zu resident keys",
915 		    fido_credman_rp_id(rp, i), nrk);
916 
917 		/* Iterate over resident keys for this RP ID */
918 		for (j = 0; j < nrk; j++) {
919 			if ((cred = fido_credman_rk(rk, j)) == NULL) {
920 				skdebug(__func__, "no RK in slot %zu", j);
921 				continue;
922 			}
923 			skdebug(__func__, "Device %s RP \"%s\" slot %zu: "
924 			    "type %d", devpath, fido_credman_rp_id(rp, i), j,
925 			    fido_cred_type(cred));
926 
927 			/* build response entry */
928 			if ((srk = calloc(1, sizeof(*srk))) == NULL ||
929 			    (srk->key.key_handle = calloc(1,
930 			    fido_cred_id_len(cred))) == NULL ||
931 			    (srk->application = strdup(fido_credman_rp_id(rp,
932 			    i))) == NULL) {
933 				skdebug(__func__, "alloc sk_resident_key");
934 				goto out;
935 			}
936 
937 			srk->key.key_handle_len = fido_cred_id_len(cred);
938 			memcpy(srk->key.key_handle,
939 			    fido_cred_id_ptr(cred),
940 			    srk->key.key_handle_len);
941 
942 			switch (fido_cred_type(cred)) {
943 			case COSE_ES256:
944 				srk->alg = SSH_SK_ECDSA;
945 				break;
946 			case COSE_EDDSA:
947 				srk->alg = SSH_SK_ED25519;
948 				break;
949 			default:
950 				skdebug(__func__, "unsupported key type %d",
951 				    fido_cred_type(cred));
952 				goto out; /* XXX free rk and continue */
953 			}
954 
955 			if ((r = pack_public_key(srk->alg, cred,
956 			    &srk->key)) != 0) {
957 				skdebug(__func__, "pack public key failed");
958 				goto out;
959 			}
960 			/* append */
961 			if ((tmp = recallocarray(*rksp, *nrksp, (*nrksp) + 1,
962 			    sizeof(**rksp))) == NULL) {
963 				skdebug(__func__, "alloc rksp");
964 				goto out;
965 			}
966 			*rksp = tmp;
967 			(*rksp)[(*nrksp)++] = srk;
968 			srk = NULL;
969 		}
970 	}
971 	/* Success */
972 	ret = 0;
973  out:
974 	if (srk != NULL) {
975 		free(srk->application);
976 		freezero(srk->key.public_key, srk->key.public_key_len);
977 		freezero(srk->key.key_handle, srk->key.key_handle_len);
978 		freezero(srk, sizeof(*srk));
979 	}
980 	fido_credman_rp_free(&rp);
981 	fido_credman_rk_free(&rk);
982 	fido_dev_close(dev);
983 	fido_dev_free(&dev);
984 	fido_credman_metadata_free(&metadata);
985 	return ret;
986 }
987 
988 int
989 sk_load_resident_keys(const char *pin, struct sk_option **options,
990     struct sk_resident_key ***rksp, size_t *nrksp)
991 {
992 	int ret = SSH_SK_ERR_GENERAL, r = -1;
993 	fido_dev_info_t *devlist = NULL;
994 	size_t i, ndev = 0, nrks = 0;
995 	const fido_dev_info_t *di;
996 	struct sk_resident_key **rks = NULL;
997 	char *device = NULL;
998 	*rksp = NULL;
999 	*nrksp = 0;
1000 
1001 	fido_init(SSH_FIDO_INIT_ARG);
1002 
1003 	if (check_sign_load_resident_options(options, &device) != 0)
1004 		goto out; /* error already logged */
1005 	if (device != NULL) {
1006 		skdebug(__func__, "trying %s", device);
1007 		if ((r = read_rks(device, pin, &rks, &nrks)) != 0) {
1008 			skdebug(__func__, "read_rks failed for %s", device);
1009 			ret = r;
1010 			goto out;
1011 		}
1012 	} else {
1013 		/* Try all devices */
1014 		if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) {
1015 			skdebug(__func__, "fido_dev_info_new failed");
1016 			goto out;
1017 		}
1018 		if ((r = fido_dev_info_manifest(devlist,
1019 		    MAX_FIDO_DEVICES, &ndev)) != FIDO_OK) {
1020 			skdebug(__func__, "fido_dev_info_manifest failed: %s",
1021 			    fido_strerr(r));
1022 			goto out;
1023 		}
1024 		for (i = 0; i < ndev; i++) {
1025 			if ((di = fido_dev_info_ptr(devlist, i)) == NULL) {
1026 				skdebug(__func__, "no dev info at %zu", i);
1027 				continue;
1028 			}
1029 			skdebug(__func__, "trying %s", fido_dev_info_path(di));
1030 			if ((r = read_rks(fido_dev_info_path(di), pin,
1031 			    &rks, &nrks)) != 0) {
1032 				skdebug(__func__, "read_rks failed for %s",
1033 				    fido_dev_info_path(di));
1034 				/* remember last error */
1035 				ret = r;
1036 				continue;
1037 			}
1038 		}
1039 	}
1040 	/* success, unless we have no keys but a specific error */
1041 	if (nrks > 0 || ret == SSH_SK_ERR_GENERAL)
1042 		ret = 0;
1043 	*rksp = rks;
1044 	*nrksp = nrks;
1045 	rks = NULL;
1046 	nrks = 0;
1047  out:
1048 	free(device);
1049 	for (i = 0; i < nrks; i++) {
1050 		free(rks[i]->application);
1051 		freezero(rks[i]->key.public_key, rks[i]->key.public_key_len);
1052 		freezero(rks[i]->key.key_handle, rks[i]->key.key_handle_len);
1053 		freezero(rks[i], sizeof(*rks[i]));
1054 	}
1055 	free(rks);
1056 	fido_dev_info_free(&devlist, MAX_FIDO_DEVICES);
1057 	return ret;
1058 }
1059 
1060 #endif /* ENABLE_SK_INTERNAL */
1061