xref: /openssh-portable/sk-usbhid.c (revision 2ad7b7e4)
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 static int
453 check_sk_extensions(fido_dev_t *dev, const char *ext, int *ret)
454 {
455 	fido_cbor_info_t *info;
456 	char * const *ptr;
457 	size_t len;
458 	int r;
459 
460 	*ret = 0;
461 
462 	if (!fido_dev_is_fido2(dev)) {
463 		skdebug(__func__, "device is not fido2");
464 		return 0;
465 	}
466 	if ((info = fido_cbor_info_new()) == NULL) {
467 		skdebug(__func__, "fido_cbor_info_new failed");
468 		return -1;
469 	}
470 	if ((r = fido_dev_get_cbor_info(dev, info)) != FIDO_OK) {
471 		skdebug(__func__, "fido_dev_get_cbor_info: %s", fido_strerr(r));
472 		fido_cbor_info_free(&info);
473 		return -1;
474 	}
475 	ptr = fido_cbor_info_extensions_ptr(info);
476 	len = fido_cbor_info_extensions_len(info);
477 	for (size_t i = 0; i < len; i++) {
478 		if (!strcmp(ptr[i], ext)) {
479 			*ret = 1;
480 			break;
481 		}
482 	}
483 	fido_cbor_info_free(&info);
484 	skdebug(__func__, "extension %s %s", ext, *ret ? "present" : "absent");
485 
486 	return 0;
487 }
488 
489 int
490 sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
491     const char *application, uint8_t flags, const char *pin,
492     struct sk_option **options, struct sk_enroll_response **enroll_response)
493 {
494 	fido_cred_t *cred = NULL;
495 	fido_dev_t *dev = NULL;
496 	const uint8_t *ptr;
497 	uint8_t user_id[32];
498 	struct sk_enroll_response *response = NULL;
499 	size_t len;
500 	int credprot;
501 	int cose_alg;
502 	int ret = SSH_SK_ERR_GENERAL;
503 	int r;
504 	char *device = NULL;
505 
506 	fido_init(SSH_FIDO_INIT_ARG);
507 
508 	if (enroll_response == NULL) {
509 		skdebug(__func__, "enroll_response == NULL");
510 		goto out;
511 	}
512 	memset(user_id, 0, sizeof(user_id));
513 	if (check_enroll_options(options, &device,
514 	    user_id, sizeof(user_id)) != 0)
515 		goto out; /* error already logged */
516 
517 	*enroll_response = NULL;
518 	switch(alg) {
519 #ifdef WITH_OPENSSL
520 	case SSH_SK_ECDSA:
521 		cose_alg = COSE_ES256;
522 		break;
523 #endif /* WITH_OPENSSL */
524 	case SSH_SK_ED25519:
525 		cose_alg = COSE_EDDSA;
526 		break;
527 	default:
528 		skdebug(__func__, "unsupported key type %d", alg);
529 		goto out;
530 	}
531 	if (device == NULL && (device = pick_first_device()) == NULL) {
532 		ret = SSH_SK_ERR_DEVICE_NOT_FOUND;
533 		skdebug(__func__, "pick_first_device failed");
534 		goto out;
535 	}
536 	skdebug(__func__, "using device %s", device);
537 	if ((cred = fido_cred_new()) == NULL) {
538 		skdebug(__func__, "fido_cred_new failed");
539 		goto out;
540 	}
541 	if ((r = fido_cred_set_type(cred, cose_alg)) != FIDO_OK) {
542 		skdebug(__func__, "fido_cred_set_type: %s", fido_strerr(r));
543 		goto out;
544 	}
545 	if ((r = fido_cred_set_clientdata_hash(cred, challenge,
546 	    challenge_len)) != FIDO_OK) {
547 		skdebug(__func__, "fido_cred_set_clientdata_hash: %s",
548 		    fido_strerr(r));
549 		goto out;
550 	}
551 	if ((r = fido_cred_set_rk(cred, (flags & SSH_SK_RESIDENT_KEY) != 0 ?
552 	    FIDO_OPT_TRUE : FIDO_OPT_OMIT)) != FIDO_OK) {
553 		skdebug(__func__, "fido_cred_set_rk: %s", fido_strerr(r));
554 		goto out;
555 	}
556 	if ((r = fido_cred_set_user(cred, user_id, sizeof(user_id),
557 	    "openssh", "openssh", NULL)) != FIDO_OK) {
558 		skdebug(__func__, "fido_cred_set_user: %s", fido_strerr(r));
559 		goto out;
560 	}
561 	if ((r = fido_cred_set_rp(cred, application, NULL)) != FIDO_OK) {
562 		skdebug(__func__, "fido_cred_set_rp: %s", fido_strerr(r));
563 		goto out;
564 	}
565 	if ((dev = fido_dev_new()) == NULL) {
566 		skdebug(__func__, "fido_dev_new failed");
567 		goto out;
568 	}
569 	if ((r = fido_dev_open(dev, device)) != FIDO_OK) {
570 		skdebug(__func__, "fido_dev_open: %s", fido_strerr(r));
571 		goto out;
572 	}
573 	if ((flags & SSH_SK_RESIDENT_KEY) != 0) {
574 		if (check_sk_extensions(dev, "credProtect", &credprot) < 0) {
575 			skdebug(__func__, "check_sk_extensions failed");
576 			goto out;
577 		}
578 		if (credprot == 0) {
579 			skdebug(__func__, "refusing to create unprotected "
580 			    "resident key");
581 			ret = SSH_SK_ERR_UNSUPPORTED;
582 			goto out;
583 		}
584 		if ((r = fido_cred_set_prot(cred,
585 		    FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID)) != FIDO_OK) {
586 			skdebug(__func__, "fido_cred_set_prot: %s",
587 			    fido_strerr(r));
588 			ret = fidoerr_to_skerr(r);
589 			goto out;
590 		}
591 	}
592 	if ((r = fido_dev_make_cred(dev, cred, pin)) != FIDO_OK) {
593 		skdebug(__func__, "fido_dev_make_cred: %s", fido_strerr(r));
594 		ret = fidoerr_to_skerr(r);
595 		goto out;
596 	}
597 	if (fido_cred_x5c_ptr(cred) != NULL) {
598 		if ((r = fido_cred_verify(cred)) != FIDO_OK) {
599 			skdebug(__func__, "fido_cred_verify: %s",
600 			    fido_strerr(r));
601 			goto out;
602 		}
603 	} else {
604 		skdebug(__func__, "self-attested credential");
605 		if ((r = fido_cred_verify_self(cred)) != FIDO_OK) {
606 			skdebug(__func__, "fido_cred_verify_self: %s",
607 			    fido_strerr(r));
608 			goto out;
609 		}
610 	}
611 	if ((response = calloc(1, sizeof(*response))) == NULL) {
612 		skdebug(__func__, "calloc response failed");
613 		goto out;
614 	}
615 	if (pack_public_key(alg, cred, response) != 0) {
616 		skdebug(__func__, "pack_public_key failed");
617 		goto out;
618 	}
619 	if ((ptr = fido_cred_id_ptr(cred)) != NULL) {
620 		len = fido_cred_id_len(cred);
621 		if ((response->key_handle = calloc(1, len)) == NULL) {
622 			skdebug(__func__, "calloc key handle failed");
623 			goto out;
624 		}
625 		memcpy(response->key_handle, ptr, len);
626 		response->key_handle_len = len;
627 	}
628 	if ((ptr = fido_cred_sig_ptr(cred)) != NULL) {
629 		len = fido_cred_sig_len(cred);
630 		if ((response->signature = calloc(1, len)) == NULL) {
631 			skdebug(__func__, "calloc signature failed");
632 			goto out;
633 		}
634 		memcpy(response->signature, ptr, len);
635 		response->signature_len = len;
636 	}
637 	if ((ptr = fido_cred_x5c_ptr(cred)) != NULL) {
638 		len = fido_cred_x5c_len(cred);
639 		debug3("%s: attestation cert len=%zu", __func__, len);
640 		if ((response->attestation_cert = calloc(1, len)) == NULL) {
641 			skdebug(__func__, "calloc attestation cert failed");
642 			goto out;
643 		}
644 		memcpy(response->attestation_cert, ptr, len);
645 		response->attestation_cert_len = len;
646 	}
647 	*enroll_response = response;
648 	response = NULL;
649 	ret = 0;
650  out:
651 	free(device);
652 	if (response != NULL) {
653 		free(response->public_key);
654 		free(response->key_handle);
655 		free(response->signature);
656 		free(response->attestation_cert);
657 		free(response);
658 	}
659 	if (dev != NULL) {
660 		fido_dev_close(dev);
661 		fido_dev_free(&dev);
662 	}
663 	if (cred != NULL) {
664 		fido_cred_free(&cred);
665 	}
666 	return ret;
667 }
668 
669 #ifdef WITH_OPENSSL
670 static int
671 pack_sig_ecdsa(fido_assert_t *assert, struct sk_sign_response *response)
672 {
673 	ECDSA_SIG *sig = NULL;
674 	const BIGNUM *sig_r, *sig_s;
675 	const unsigned char *cp;
676 	size_t sig_len;
677 	int ret = -1;
678 
679 	cp = fido_assert_sig_ptr(assert, 0);
680 	sig_len = fido_assert_sig_len(assert, 0);
681 	if ((sig = d2i_ECDSA_SIG(NULL, &cp, sig_len)) == NULL) {
682 		skdebug(__func__, "d2i_ECDSA_SIG failed");
683 		goto out;
684 	}
685 	ECDSA_SIG_get0(sig, &sig_r, &sig_s);
686 	response->sig_r_len = BN_num_bytes(sig_r);
687 	response->sig_s_len = BN_num_bytes(sig_s);
688 	if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL ||
689 	    (response->sig_s = calloc(1, response->sig_s_len)) == NULL) {
690 		skdebug(__func__, "calloc signature failed");
691 		goto out;
692 	}
693 	BN_bn2bin(sig_r, response->sig_r);
694 	BN_bn2bin(sig_s, response->sig_s);
695 	ret = 0;
696  out:
697 	ECDSA_SIG_free(sig);
698 	if (ret != 0) {
699 		free(response->sig_r);
700 		free(response->sig_s);
701 		response->sig_r = NULL;
702 		response->sig_s = NULL;
703 	}
704 	return ret;
705 }
706 #endif /* WITH_OPENSSL */
707 
708 static int
709 pack_sig_ed25519(fido_assert_t *assert, struct sk_sign_response *response)
710 {
711 	const unsigned char *ptr;
712 	size_t len;
713 	int ret = -1;
714 
715 	ptr = fido_assert_sig_ptr(assert, 0);
716 	len = fido_assert_sig_len(assert, 0);
717 	if (len != 64) {
718 		skdebug(__func__, "bad length %zu", len);
719 		goto out;
720 	}
721 	response->sig_r_len = len;
722 	if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL) {
723 		skdebug(__func__, "calloc signature failed");
724 		goto out;
725 	}
726 	memcpy(response->sig_r, ptr, len);
727 	ret = 0;
728  out:
729 	if (ret != 0) {
730 		free(response->sig_r);
731 		response->sig_r = NULL;
732 	}
733 	return ret;
734 }
735 
736 static int
737 pack_sig(uint32_t  alg, fido_assert_t *assert,
738     struct sk_sign_response *response)
739 {
740 	switch(alg) {
741 #ifdef WITH_OPENSSL
742 	case SSH_SK_ECDSA:
743 		return pack_sig_ecdsa(assert, response);
744 #endif /* WITH_OPENSSL */
745 	case SSH_SK_ED25519:
746 		return pack_sig_ed25519(assert, response);
747 	default:
748 		return -1;
749 	}
750 }
751 
752 /* Checks sk_options for sk_sign() and sk_load_resident_keys() */
753 static int
754 check_sign_load_resident_options(struct sk_option **options, char **devicep)
755 {
756 	size_t i;
757 
758 	if (options == NULL)
759 		return 0;
760 	for (i = 0; options[i] != NULL; i++) {
761 		if (strcmp(options[i]->name, "device") == 0) {
762 			if ((*devicep = strdup(options[i]->value)) == NULL) {
763 				skdebug(__func__, "strdup device failed");
764 				return -1;
765 			}
766 			skdebug(__func__, "requested device %s", *devicep);
767 		} else {
768 			skdebug(__func__, "requested unsupported option %s",
769 			    options[i]->name);
770 			if (options[i]->required) {
771 				skdebug(__func__, "unknown required option");
772 				return -1;
773 			}
774 		}
775 	}
776 	return 0;
777 }
778 
779 /* Calculate SHA256(m) */
780 static int
781 sha256_mem(const void *m, size_t mlen, u_char *d, size_t dlen)
782 {
783 #ifdef WITH_OPENSSL
784 	u_int mdlen;
785 #endif
786 
787 	if (dlen != 32)
788 		return -1;
789 #ifdef WITH_OPENSSL
790 	mdlen = dlen;
791 	if (!EVP_Digest(m, mlen, d, &mdlen, EVP_sha256(), NULL))
792 		return -1;
793 #else
794 	SHA256Data(m, mlen, d);
795 #endif
796 	return 0;
797 }
798 
799 int
800 sk_sign(uint32_t alg, const uint8_t *data, size_t datalen,
801     const char *application,
802     const uint8_t *key_handle, size_t key_handle_len,
803     uint8_t flags, const char *pin, struct sk_option **options,
804     struct sk_sign_response **sign_response)
805 {
806 	fido_assert_t *assert = NULL;
807 	char *device = NULL;
808 	fido_dev_t *dev = NULL;
809 	struct sk_sign_response *response = NULL;
810 	uint8_t message[32];
811 	int ret = SSH_SK_ERR_GENERAL;
812 	int r;
813 
814 	fido_init(SSH_FIDO_INIT_ARG);
815 
816 	if (sign_response == NULL) {
817 		skdebug(__func__, "sign_response == NULL");
818 		goto out;
819 	}
820 	*sign_response = NULL;
821 	if (check_sign_load_resident_options(options, &device) != 0)
822 		goto out; /* error already logged */
823 	/* hash data to be signed before it goes to the security key */
824 	if ((r = sha256_mem(data, datalen, message, sizeof(message))) != 0) {
825 		skdebug(__func__, "hash message failed");
826 		goto out;
827 	}
828 	if ((dev = find_device(device, message, sizeof(message),
829 	    application, key_handle, key_handle_len)) == NULL) {
830 		skdebug(__func__, "couldn't find device for key handle");
831 		goto out;
832 	}
833 	if ((assert = fido_assert_new()) == NULL) {
834 		skdebug(__func__, "fido_assert_new failed");
835 		goto out;
836 	}
837 	if ((r = fido_assert_set_clientdata_hash(assert, message,
838 	    sizeof(message))) != FIDO_OK) {
839 		skdebug(__func__, "fido_assert_set_clientdata_hash: %s",
840 		    fido_strerr(r));
841 		goto out;
842 	}
843 	if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK) {
844 		skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r));
845 		goto out;
846 	}
847 	if ((r = fido_assert_allow_cred(assert, key_handle,
848 	    key_handle_len)) != FIDO_OK) {
849 		skdebug(__func__, "fido_assert_allow_cred: %s", fido_strerr(r));
850 		goto out;
851 	}
852 	if ((r = fido_assert_set_up(assert,
853 	    (flags & SSH_SK_USER_PRESENCE_REQD) ?
854 	    FIDO_OPT_TRUE : FIDO_OPT_FALSE)) != FIDO_OK) {
855 		skdebug(__func__, "fido_assert_set_up: %s", fido_strerr(r));
856 		goto out;
857 	}
858 	if ((r = fido_dev_get_assert(dev, assert, NULL)) != FIDO_OK) {
859 		skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
860 		goto out;
861 	}
862 	if ((response = calloc(1, sizeof(*response))) == NULL) {
863 		skdebug(__func__, "calloc response failed");
864 		goto out;
865 	}
866 	response->flags = fido_assert_flags(assert, 0);
867 	response->counter = fido_assert_sigcount(assert, 0);
868 	if (pack_sig(alg, assert, response) != 0) {
869 		skdebug(__func__, "pack_sig failed");
870 		goto out;
871 	}
872 	*sign_response = response;
873 	response = NULL;
874 	ret = 0;
875  out:
876 	explicit_bzero(message, sizeof(message));
877 	free(device);
878 	if (response != NULL) {
879 		free(response->sig_r);
880 		free(response->sig_s);
881 		free(response);
882 	}
883 	if (dev != NULL) {
884 		fido_dev_close(dev);
885 		fido_dev_free(&dev);
886 	}
887 	if (assert != NULL) {
888 		fido_assert_free(&assert);
889 	}
890 	return ret;
891 }
892 
893 static int
894 read_rks(const char *devpath, const char *pin,
895     struct sk_resident_key ***rksp, size_t *nrksp)
896 {
897 	int ret = SSH_SK_ERR_GENERAL, r = -1;
898 	fido_dev_t *dev = NULL;
899 	fido_credman_metadata_t *metadata = NULL;
900 	fido_credman_rp_t *rp = NULL;
901 	fido_credman_rk_t *rk = NULL;
902 	size_t i, j, nrp, nrk;
903 	const fido_cred_t *cred;
904 	struct sk_resident_key *srk = NULL, **tmp;
905 
906 	if ((dev = fido_dev_new()) == NULL) {
907 		skdebug(__func__, "fido_dev_new failed");
908 		return ret;
909 	}
910 	if ((r = fido_dev_open(dev, devpath)) != FIDO_OK) {
911 		skdebug(__func__, "fido_dev_open %s failed: %s",
912 		    devpath, fido_strerr(r));
913 		fido_dev_free(&dev);
914 		return ret;
915 	}
916 	if ((metadata = fido_credman_metadata_new()) == NULL) {
917 		skdebug(__func__, "alloc failed");
918 		goto out;
919 	}
920 
921 	if ((r = fido_credman_get_dev_metadata(dev, metadata, pin)) != 0) {
922 		if (r == FIDO_ERR_INVALID_COMMAND) {
923 			skdebug(__func__, "device %s does not support "
924 			    "resident keys", devpath);
925 			ret = 0;
926 			goto out;
927 		}
928 		skdebug(__func__, "get metadata for %s failed: %s",
929 		    devpath, fido_strerr(r));
930 		ret = fidoerr_to_skerr(r);
931 		goto out;
932 	}
933 	skdebug(__func__, "existing %llu, remaining %llu",
934 	    (unsigned long long)fido_credman_rk_existing(metadata),
935 	    (unsigned long long)fido_credman_rk_remaining(metadata));
936 	if ((rp = fido_credman_rp_new()) == NULL) {
937 		skdebug(__func__, "alloc rp failed");
938 		goto out;
939 	}
940 	if ((r = fido_credman_get_dev_rp(dev, rp, pin)) != 0) {
941 		skdebug(__func__, "get RPs for %s failed: %s",
942 		    devpath, fido_strerr(r));
943 		goto out;
944 	}
945 	nrp = fido_credman_rp_count(rp);
946 	skdebug(__func__, "Device %s has resident keys for %zu RPs",
947 	    devpath, nrp);
948 
949 	/* Iterate over RP IDs that have resident keys */
950 	for (i = 0; i < nrp; i++) {
951 		skdebug(__func__, "rp %zu: name=\"%s\" id=\"%s\" hashlen=%zu",
952 		    i, fido_credman_rp_name(rp, i), fido_credman_rp_id(rp, i),
953 		    fido_credman_rp_id_hash_len(rp, i));
954 
955 		/* Skip non-SSH RP IDs */
956 		if (strncasecmp(fido_credman_rp_id(rp, i), "ssh:", 4) != 0)
957 			continue;
958 
959 		fido_credman_rk_free(&rk);
960 		if ((rk = fido_credman_rk_new()) == NULL) {
961 			skdebug(__func__, "alloc rk failed");
962 			goto out;
963 		}
964 		if ((r = fido_credman_get_dev_rk(dev, fido_credman_rp_id(rp, i),
965 		    rk, pin)) != 0) {
966 			skdebug(__func__, "get RKs for %s slot %zu failed: %s",
967 			    devpath, i, fido_strerr(r));
968 			goto out;
969 		}
970 		nrk = fido_credman_rk_count(rk);
971 		skdebug(__func__, "RP \"%s\" has %zu resident keys",
972 		    fido_credman_rp_id(rp, i), nrk);
973 
974 		/* Iterate over resident keys for this RP ID */
975 		for (j = 0; j < nrk; j++) {
976 			if ((cred = fido_credman_rk(rk, j)) == NULL) {
977 				skdebug(__func__, "no RK in slot %zu", j);
978 				continue;
979 			}
980 			skdebug(__func__, "Device %s RP \"%s\" slot %zu: "
981 			    "type %d", devpath, fido_credman_rp_id(rp, i), j,
982 			    fido_cred_type(cred));
983 
984 			/* build response entry */
985 			if ((srk = calloc(1, sizeof(*srk))) == NULL ||
986 			    (srk->key.key_handle = calloc(1,
987 			    fido_cred_id_len(cred))) == NULL ||
988 			    (srk->application = strdup(fido_credman_rp_id(rp,
989 			    i))) == NULL) {
990 				skdebug(__func__, "alloc sk_resident_key");
991 				goto out;
992 			}
993 
994 			srk->key.key_handle_len = fido_cred_id_len(cred);
995 			memcpy(srk->key.key_handle,
996 			    fido_cred_id_ptr(cred),
997 			    srk->key.key_handle_len);
998 
999 			switch (fido_cred_type(cred)) {
1000 			case COSE_ES256:
1001 				srk->alg = SSH_SK_ECDSA;
1002 				break;
1003 			case COSE_EDDSA:
1004 				srk->alg = SSH_SK_ED25519;
1005 				break;
1006 			default:
1007 				skdebug(__func__, "unsupported key type %d",
1008 				    fido_cred_type(cred));
1009 				goto out; /* XXX free rk and continue */
1010 			}
1011 
1012 			if ((r = pack_public_key(srk->alg, cred,
1013 			    &srk->key)) != 0) {
1014 				skdebug(__func__, "pack public key failed");
1015 				goto out;
1016 			}
1017 			/* append */
1018 			if ((tmp = recallocarray(*rksp, *nrksp, (*nrksp) + 1,
1019 			    sizeof(**rksp))) == NULL) {
1020 				skdebug(__func__, "alloc rksp");
1021 				goto out;
1022 			}
1023 			*rksp = tmp;
1024 			(*rksp)[(*nrksp)++] = srk;
1025 			srk = NULL;
1026 		}
1027 	}
1028 	/* Success */
1029 	ret = 0;
1030  out:
1031 	if (srk != NULL) {
1032 		free(srk->application);
1033 		freezero(srk->key.public_key, srk->key.public_key_len);
1034 		freezero(srk->key.key_handle, srk->key.key_handle_len);
1035 		freezero(srk, sizeof(*srk));
1036 	}
1037 	fido_credman_rp_free(&rp);
1038 	fido_credman_rk_free(&rk);
1039 	fido_dev_close(dev);
1040 	fido_dev_free(&dev);
1041 	fido_credman_metadata_free(&metadata);
1042 	return ret;
1043 }
1044 
1045 int
1046 sk_load_resident_keys(const char *pin, struct sk_option **options,
1047     struct sk_resident_key ***rksp, size_t *nrksp)
1048 {
1049 	int ret = SSH_SK_ERR_GENERAL, r = -1;
1050 	fido_dev_info_t *devlist = NULL;
1051 	size_t i, ndev = 0, nrks = 0;
1052 	const fido_dev_info_t *di;
1053 	struct sk_resident_key **rks = NULL;
1054 	char *device = NULL;
1055 	*rksp = NULL;
1056 	*nrksp = 0;
1057 
1058 	fido_init(SSH_FIDO_INIT_ARG);
1059 
1060 	if (check_sign_load_resident_options(options, &device) != 0)
1061 		goto out; /* error already logged */
1062 	if (device != NULL) {
1063 		skdebug(__func__, "trying %s", device);
1064 		if ((r = read_rks(device, pin, &rks, &nrks)) != 0) {
1065 			skdebug(__func__, "read_rks failed for %s", device);
1066 			ret = r;
1067 			goto out;
1068 		}
1069 	} else {
1070 		/* Try all devices */
1071 		if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) {
1072 			skdebug(__func__, "fido_dev_info_new failed");
1073 			goto out;
1074 		}
1075 		if ((r = fido_dev_info_manifest(devlist,
1076 		    MAX_FIDO_DEVICES, &ndev)) != FIDO_OK) {
1077 			skdebug(__func__, "fido_dev_info_manifest failed: %s",
1078 			    fido_strerr(r));
1079 			goto out;
1080 		}
1081 		for (i = 0; i < ndev; i++) {
1082 			if ((di = fido_dev_info_ptr(devlist, i)) == NULL) {
1083 				skdebug(__func__, "no dev info at %zu", i);
1084 				continue;
1085 			}
1086 			skdebug(__func__, "trying %s", fido_dev_info_path(di));
1087 			if ((r = read_rks(fido_dev_info_path(di), pin,
1088 			    &rks, &nrks)) != 0) {
1089 				skdebug(__func__, "read_rks failed for %s",
1090 				    fido_dev_info_path(di));
1091 				/* remember last error */
1092 				ret = r;
1093 				continue;
1094 			}
1095 		}
1096 	}
1097 	/* success, unless we have no keys but a specific error */
1098 	if (nrks > 0 || ret == SSH_SK_ERR_GENERAL)
1099 		ret = 0;
1100 	*rksp = rks;
1101 	*nrksp = nrks;
1102 	rks = NULL;
1103 	nrks = 0;
1104  out:
1105 	free(device);
1106 	for (i = 0; i < nrks; i++) {
1107 		free(rks[i]->application);
1108 		freezero(rks[i]->key.public_key, rks[i]->key.public_key_len);
1109 		freezero(rks[i]->key.key_handle, rks[i]->key.key_handle_len);
1110 		freezero(rks[i], sizeof(*rks[i]));
1111 	}
1112 	free(rks);
1113 	fido_dev_info_free(&devlist, MAX_FIDO_DEVICES);
1114 	return ret;
1115 }
1116 
1117 #endif /* ENABLE_SK_INTERNAL */
1118