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