Annotation of src/usr.bin/ssh/sk-usbhid.c, Revision 1.8
1.1 djm 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:
1.7 naddy 24: #ifdef WITH_OPENSSL
1.1 djm 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>
1.7 naddy 30: #endif /* WITH_OPENSSL */
1.1 djm 31:
32: #include <fido.h>
33:
34: #ifndef SK_STANDALONE
35: #include "log.h"
36: #include "xmalloc.h"
37: #endif
38:
39: /* #define SK_DEBUG 1 */
40:
41: #define MAX_FIDO_DEVICES 256
42:
43: /* Compatibility with OpenSSH 1.0.x */
44: #if (OPENSSL_VERSION_NUMBER < 0x10100000L)
45: #define ECDSA_SIG_get0(sig, pr, ps) \
46: do { \
47: (*pr) = sig->r; \
48: (*ps) = sig->s; \
49: } while (0)
50: #endif
51:
52: #define SK_VERSION_MAJOR 0x00020000 /* current API version */
53:
54: /* Flags */
1.8 ! djm 55: #define SK_USER_PRESENCE_REQD 0x01
! 56: #define SK_USER_VERIFICATION_REQD 0x04
! 57: #define SK_RESIDENT_KEY 0x20
1.1 djm 58:
59: /* Algs */
60: #define SK_ECDSA 0x00
61: #define SK_ED25519 0x01
62:
63: struct sk_enroll_response {
64: uint8_t *public_key;
65: size_t public_key_len;
66: uint8_t *key_handle;
67: size_t key_handle_len;
68: uint8_t *signature;
69: size_t signature_len;
70: uint8_t *attestation_cert;
71: size_t attestation_cert_len;
72: };
73:
74: struct sk_sign_response {
75: uint8_t flags;
76: uint32_t counter;
77: uint8_t *sig_r;
78: size_t sig_r_len;
79: uint8_t *sig_s;
80: size_t sig_s_len;
81: };
82:
83: /* If building as part of OpenSSH, then rename exported functions */
84: #if !defined(SK_STANDALONE)
85: #define sk_api_version ssh_sk_api_version
86: #define sk_enroll ssh_sk_enroll
87: #define sk_sign ssh_sk_sign
88: #endif
89:
90: /* Return the version of the middleware API */
91: uint32_t sk_api_version(void);
92:
93: /* Enroll a U2F key (private key generation) */
94: int sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len,
95: const char *application, uint8_t flags,
96: struct sk_enroll_response **enroll_response);
97:
98: /* Sign a challenge */
99: int sk_sign(int alg, const uint8_t *message, size_t message_len,
100: const char *application, const uint8_t *key_handle, size_t key_handle_len,
101: uint8_t flags, struct sk_sign_response **sign_response);
102:
103: static void skdebug(const char *func, const char *fmt, ...)
104: __attribute__((__format__ (printf, 2, 3)));
105:
106: static void
107: skdebug(const char *func, const char *fmt, ...)
108: {
109: #if !defined(SK_STANDALONE)
110: char *msg;
111: va_list ap;
112:
113: va_start(ap, fmt);
114: xvasprintf(&msg, fmt, ap);
115: va_end(ap);
1.2 djm 116: debug("%s: %s", func, msg);
1.1 djm 117: free(msg);
118: #elif defined(SK_DEBUG)
119: va_list ap;
120:
121: va_start(ap, fmt);
122: fprintf(stderr, "%s: ", func);
123: vfprintf(stderr, fmt, ap);
124: fputc('\n', stderr);
125: va_end(ap);
126: #else
127: (void)func; /* XXX */
128: (void)fmt; /* XXX */
129: #endif
130: }
131:
132: uint32_t
133: sk_api_version(void)
134: {
135: return SK_VERSION_MAJOR;
136: }
137:
138: /* Select the first identified FIDO device attached to the system */
139: static char *
140: pick_first_device(void)
141: {
142: char *ret = NULL;
143: fido_dev_info_t *devlist = NULL;
144: size_t olen = 0;
145: int r;
146: const fido_dev_info_t *di;
147:
148: if ((devlist = fido_dev_info_new(1)) == NULL) {
149: skdebug(__func__, "fido_dev_info_new failed");
150: goto out;
151: }
152: if ((r = fido_dev_info_manifest(devlist, 1, &olen)) != FIDO_OK) {
153: skdebug(__func__, "fido_dev_info_manifest failed: %s",
154: fido_strerr(r));
155: goto out;
156: }
157: if (olen != 1) {
158: skdebug(__func__, "fido_dev_info_manifest bad len %zu", olen);
159: goto out;
160: }
161: di = fido_dev_info_ptr(devlist, 0);
162: if ((ret = strdup(fido_dev_info_path(di))) == NULL) {
163: skdebug(__func__, "fido_dev_info_path failed");
164: goto out;
165: }
166: out:
167: fido_dev_info_free(&devlist, 1);
168: return ret;
169: }
170:
171: /* Check if the specified key handle exists on a given device. */
172: static int
173: try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len,
174: const char *application, const uint8_t *key_handle, size_t key_handle_len)
175: {
176: fido_assert_t *assert = NULL;
177: int r = FIDO_ERR_INTERNAL;
178:
179: if ((assert = fido_assert_new()) == NULL) {
180: skdebug(__func__, "fido_assert_new failed");
181: goto out;
182: }
183: if ((r = fido_assert_set_clientdata_hash(assert, message,
184: message_len)) != FIDO_OK) {
185: skdebug(__func__, "fido_assert_set_clientdata_hash: %s",
186: fido_strerr(r));
187: goto out;
188: }
189: if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK) {
190: skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r));
191: goto out;
192: }
193: if ((r = fido_assert_allow_cred(assert, key_handle,
194: key_handle_len)) != FIDO_OK) {
195: skdebug(__func__, "fido_assert_allow_cred: %s", fido_strerr(r));
196: goto out;
197: }
198: if ((r = fido_assert_set_up(assert, FIDO_OPT_FALSE)) != FIDO_OK) {
199: skdebug(__func__, "fido_assert_up: %s", fido_strerr(r));
200: goto out;
201: }
202: r = fido_dev_get_assert(dev, assert, NULL);
203: skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
1.3 djm 204: if (r == FIDO_ERR_USER_PRESENCE_REQUIRED) {
205: /* U2F tokens may return this */
206: r = FIDO_OK;
207: }
1.1 djm 208: out:
209: fido_assert_free(&assert);
210:
211: return r != FIDO_OK ? -1 : 0;
212: }
213:
214: /* Iterate over configured devices looking for a specific key handle */
215: static fido_dev_t *
216: find_device(const uint8_t *message, size_t message_len, const char *application,
217: const uint8_t *key_handle, size_t key_handle_len)
218: {
219: fido_dev_info_t *devlist = NULL;
220: fido_dev_t *dev = NULL;
1.4 deraadt 221: size_t devlist_len = 0, i;
1.1 djm 222: const char *path;
223: int r;
224:
225: if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) {
226: skdebug(__func__, "fido_dev_info_new failed");
227: goto out;
228: }
229: if ((r = fido_dev_info_manifest(devlist, MAX_FIDO_DEVICES,
230: &devlist_len)) != FIDO_OK) {
231: skdebug(__func__, "fido_dev_info_manifest: %s", fido_strerr(r));
232: goto out;
233: }
234:
235: skdebug(__func__, "found %zu device(s)", devlist_len);
236:
1.4 deraadt 237: for (i = 0; i < devlist_len; i++) {
1.1 djm 238: const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i);
239:
240: if (di == NULL) {
241: skdebug(__func__, "fido_dev_info_ptr %zu failed", i);
242: continue;
243: }
244: if ((path = fido_dev_info_path(di)) == NULL) {
245: skdebug(__func__, "fido_dev_info_path %zu failed", i);
246: continue;
247: }
248: skdebug(__func__, "trying device %zu: %s", i, path);
249: if ((dev = fido_dev_new()) == NULL) {
250: skdebug(__func__, "fido_dev_new failed");
251: continue;
252: }
253: if ((r = fido_dev_open(dev, path)) != FIDO_OK) {
254: skdebug(__func__, "fido_dev_open failed");
255: fido_dev_free(&dev);
256: continue;
257: }
258: if (try_device(dev, message, message_len, application,
259: key_handle, key_handle_len) == 0) {
260: skdebug(__func__, "found key");
261: break;
262: }
263: fido_dev_close(dev);
264: fido_dev_free(&dev);
265: }
266:
267: out:
268: if (devlist != NULL)
269: fido_dev_info_free(&devlist, MAX_FIDO_DEVICES);
270:
271: return dev;
272: }
273:
1.7 naddy 274: #ifdef WITH_OPENSSL
1.1 djm 275: /*
276: * The key returned via fido_cred_pubkey_ptr() is in affine coordinates,
277: * but the API expects a SEC1 octet string.
278: */
279: static int
280: pack_public_key_ecdsa(fido_cred_t *cred, struct sk_enroll_response *response)
281: {
282: const uint8_t *ptr;
283: BIGNUM *x = NULL, *y = NULL;
284: EC_POINT *q = NULL;
285: EC_GROUP *g = NULL;
286: int ret = -1;
287:
288: response->public_key = NULL;
289: response->public_key_len = 0;
290:
1.5 djm 291: if ((x = BN_new()) == NULL ||
292: (y = BN_new()) == NULL ||
1.1 djm 293: (g = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)) == NULL ||
294: (q = EC_POINT_new(g)) == NULL) {
295: skdebug(__func__, "libcrypto setup failed");
296: goto out;
297: }
298: if ((ptr = fido_cred_pubkey_ptr(cred)) == NULL) {
299: skdebug(__func__, "fido_cred_pubkey_ptr failed");
300: goto out;
301: }
302: if (fido_cred_pubkey_len(cred) != 64) {
303: skdebug(__func__, "bad fido_cred_pubkey_len %zu",
304: fido_cred_pubkey_len(cred));
305: goto out;
306: }
307:
308: if (BN_bin2bn(ptr, 32, x) == NULL ||
309: BN_bin2bn(ptr + 32, 32, y) == NULL) {
310: skdebug(__func__, "BN_bin2bn failed");
311: goto out;
312: }
1.5 djm 313: if (EC_POINT_set_affine_coordinates_GFp(g, q, x, y, NULL) != 1) {
1.1 djm 314: skdebug(__func__, "EC_POINT_set_affine_coordinates_GFp failed");
315: goto out;
316: }
317: response->public_key_len = EC_POINT_point2oct(g, q,
1.5 djm 318: POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
1.1 djm 319: if (response->public_key_len == 0 || response->public_key_len > 2048) {
320: skdebug(__func__, "bad pubkey length %zu",
321: response->public_key_len);
322: goto out;
323: }
324: if ((response->public_key = malloc(response->public_key_len)) == NULL) {
325: skdebug(__func__, "malloc pubkey failed");
326: goto out;
327: }
328: if (EC_POINT_point2oct(g, q, POINT_CONVERSION_UNCOMPRESSED,
1.5 djm 329: response->public_key, response->public_key_len, NULL) == 0) {
1.1 djm 330: skdebug(__func__, "EC_POINT_point2oct failed");
331: goto out;
332: }
333: /* success */
334: ret = 0;
335: out:
336: if (ret != 0 && response->public_key != NULL) {
337: memset(response->public_key, 0, response->public_key_len);
338: free(response->public_key);
339: response->public_key = NULL;
340: }
341: EC_POINT_free(q);
342: EC_GROUP_free(g);
1.5 djm 343: BN_clear_free(x);
344: BN_clear_free(y);
1.1 djm 345: return ret;
346: }
1.7 naddy 347: #endif /* WITH_OPENSSL */
1.1 djm 348:
349: static int
350: pack_public_key_ed25519(fido_cred_t *cred, struct sk_enroll_response *response)
351: {
352: const uint8_t *ptr;
353: size_t len;
354: int ret = -1;
355:
356: response->public_key = NULL;
357: response->public_key_len = 0;
358:
359: if ((len = fido_cred_pubkey_len(cred)) != 32) {
360: skdebug(__func__, "bad fido_cred_pubkey_len len %zu", len);
361: goto out;
362: }
363: if ((ptr = fido_cred_pubkey_ptr(cred)) == NULL) {
364: skdebug(__func__, "fido_cred_pubkey_ptr failed");
365: goto out;
366: }
367: response->public_key_len = len;
368: if ((response->public_key = malloc(response->public_key_len)) == NULL) {
369: skdebug(__func__, "malloc pubkey failed");
370: goto out;
371: }
372: memcpy(response->public_key, ptr, len);
373: ret = 0;
374: out:
375: if (ret != 0)
376: free(response->public_key);
377: return ret;
378: }
379:
380: static int
381: pack_public_key(int alg, fido_cred_t *cred, struct sk_enroll_response *response)
382: {
383: switch(alg) {
1.7 naddy 384: #ifdef WITH_OPENSSL
1.1 djm 385: case SK_ECDSA:
386: return pack_public_key_ecdsa(cred, response);
1.7 naddy 387: #endif /* WITH_OPENSSL */
1.1 djm 388: case SK_ED25519:
389: return pack_public_key_ed25519(cred, response);
390: default:
391: return -1;
392: }
393: }
394:
395: int
396: sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len,
397: const char *application, uint8_t flags,
1.6 markus 398: struct sk_enroll_response **enroll_response)
1.1 djm 399: {
400: fido_cred_t *cred = NULL;
401: fido_dev_t *dev = NULL;
402: const uint8_t *ptr;
403: uint8_t user_id[32];
404: struct sk_enroll_response *response = NULL;
405: size_t len;
406: int cose_alg;
407: int ret = -1;
408: int r;
409: char *device = NULL;
410:
411: #ifdef SK_DEBUG
412: fido_init(FIDO_DEBUG);
413: #endif
1.6 markus 414: if (enroll_response == NULL) {
415: skdebug(__func__, "enroll_response == NULL");
1.1 djm 416: goto out;
417: }
1.6 markus 418: *enroll_response = NULL;
1.1 djm 419: switch(alg) {
1.7 naddy 420: #ifdef WITH_OPENSSL
1.1 djm 421: case SK_ECDSA:
422: cose_alg = COSE_ES256;
423: break;
1.7 naddy 424: #endif /* WITH_OPENSSL */
1.1 djm 425: case SK_ED25519:
426: cose_alg = COSE_EDDSA;
427: break;
428: default:
429: skdebug(__func__, "unsupported key type %d", alg);
430: goto out;
431: }
432: if ((device = pick_first_device()) == NULL) {
433: skdebug(__func__, "pick_first_device failed");
434: goto out;
435: }
436: skdebug(__func__, "using device %s", device);
437: if ((cred = fido_cred_new()) == NULL) {
438: skdebug(__func__, "fido_cred_new failed");
439: goto out;
440: }
441: memset(user_id, 0, sizeof(user_id));
442: if ((r = fido_cred_set_type(cred, cose_alg)) != FIDO_OK) {
443: skdebug(__func__, "fido_cred_set_type: %s", fido_strerr(r));
444: goto out;
445: }
446: if ((r = fido_cred_set_clientdata_hash(cred, challenge,
447: challenge_len)) != FIDO_OK) {
448: skdebug(__func__, "fido_cred_set_clientdata_hash: %s",
449: fido_strerr(r));
1.8 ! djm 450: goto out;
! 451: }
! 452: if ((r = fido_cred_set_rk(cred, (flags & SK_RESIDENT_KEY) != 0 ?
! 453: FIDO_OPT_TRUE : FIDO_OPT_OMIT)) != FIDO_OK) {
! 454: skdebug(__func__, "fido_cred_set_rk: %s", fido_strerr(r));
1.1 djm 455: goto out;
456: }
457: if ((r = fido_cred_set_user(cred, user_id, sizeof(user_id),
458: "openssh", "openssh", NULL)) != FIDO_OK) {
459: skdebug(__func__, "fido_cred_set_user: %s", fido_strerr(r));
460: goto out;
461: }
462: if ((r = fido_cred_set_rp(cred, application, NULL)) != FIDO_OK) {
463: skdebug(__func__, "fido_cred_set_rp: %s", fido_strerr(r));
464: goto out;
465: }
466: if ((dev = fido_dev_new()) == NULL) {
467: skdebug(__func__, "fido_dev_new failed");
468: goto out;
469: }
470: if ((r = fido_dev_open(dev, device)) != FIDO_OK) {
471: skdebug(__func__, "fido_dev_open: %s", fido_strerr(r));
472: goto out;
473: }
474: if ((r = fido_dev_make_cred(dev, cred, NULL)) != FIDO_OK) {
475: skdebug(__func__, "fido_dev_make_cred: %s", fido_strerr(r));
476: goto out;
477: }
478: if (fido_cred_x5c_ptr(cred) != NULL) {
479: if ((r = fido_cred_verify(cred)) != FIDO_OK) {
480: skdebug(__func__, "fido_cred_verify: %s",
481: fido_strerr(r));
482: goto out;
483: }
484: } else {
485: skdebug(__func__, "self-attested credential");
486: if ((r = fido_cred_verify_self(cred)) != FIDO_OK) {
487: skdebug(__func__, "fido_cred_verify_self: %s",
488: fido_strerr(r));
489: goto out;
490: }
491: }
492: if ((response = calloc(1, sizeof(*response))) == NULL) {
493: skdebug(__func__, "calloc response failed");
494: goto out;
495: }
496: if (pack_public_key(alg, cred, response) != 0) {
497: skdebug(__func__, "pack_public_key failed");
498: goto out;
499: }
500: if ((ptr = fido_cred_id_ptr(cred)) != NULL) {
501: len = fido_cred_id_len(cred);
502: if ((response->key_handle = calloc(1, len)) == NULL) {
503: skdebug(__func__, "calloc key handle failed");
504: goto out;
505: }
506: memcpy(response->key_handle, ptr, len);
507: response->key_handle_len = len;
508: }
509: if ((ptr = fido_cred_sig_ptr(cred)) != NULL) {
510: len = fido_cred_sig_len(cred);
511: if ((response->signature = calloc(1, len)) == NULL) {
512: skdebug(__func__, "calloc signature failed");
513: goto out;
514: }
515: memcpy(response->signature, ptr, len);
516: response->signature_len = len;
517: }
518: if ((ptr = fido_cred_x5c_ptr(cred)) != NULL) {
519: len = fido_cred_x5c_len(cred);
520: if ((response->attestation_cert = calloc(1, len)) == NULL) {
521: skdebug(__func__, "calloc attestation cert failed");
522: goto out;
523: }
524: memcpy(response->attestation_cert, ptr, len);
525: response->attestation_cert_len = len;
526: }
1.6 markus 527: *enroll_response = response;
1.1 djm 528: response = NULL;
529: ret = 0;
530: out:
531: free(device);
532: if (response != NULL) {
533: free(response->public_key);
534: free(response->key_handle);
535: free(response->signature);
536: free(response->attestation_cert);
537: free(response);
538: }
539: if (dev != NULL) {
540: fido_dev_close(dev);
541: fido_dev_free(&dev);
542: }
543: if (cred != NULL) {
544: fido_cred_free(&cred);
545: }
546: return ret;
547: }
548:
1.7 naddy 549: #ifdef WITH_OPENSSL
1.1 djm 550: static int
551: pack_sig_ecdsa(fido_assert_t *assert, struct sk_sign_response *response)
552: {
553: ECDSA_SIG *sig = NULL;
554: const BIGNUM *sig_r, *sig_s;
555: const unsigned char *cp;
556: size_t sig_len;
557: int ret = -1;
558:
559: cp = fido_assert_sig_ptr(assert, 0);
560: sig_len = fido_assert_sig_len(assert, 0);
561: if ((sig = d2i_ECDSA_SIG(NULL, &cp, sig_len)) == NULL) {
562: skdebug(__func__, "d2i_ECDSA_SIG failed");
563: goto out;
564: }
565: ECDSA_SIG_get0(sig, &sig_r, &sig_s);
566: response->sig_r_len = BN_num_bytes(sig_r);
567: response->sig_s_len = BN_num_bytes(sig_s);
568: if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL ||
569: (response->sig_s = calloc(1, response->sig_s_len)) == NULL) {
570: skdebug(__func__, "calloc signature failed");
571: goto out;
572: }
573: BN_bn2bin(sig_r, response->sig_r);
574: BN_bn2bin(sig_s, response->sig_s);
575: ret = 0;
576: out:
577: ECDSA_SIG_free(sig);
578: if (ret != 0) {
579: free(response->sig_r);
580: free(response->sig_s);
581: response->sig_r = NULL;
582: response->sig_s = NULL;
583: }
584: return ret;
585: }
1.7 naddy 586: #endif /* WITH_OPENSSL */
1.1 djm 587:
588: static int
589: pack_sig_ed25519(fido_assert_t *assert, struct sk_sign_response *response)
590: {
591: const unsigned char *ptr;
592: size_t len;
593: int ret = -1;
594:
595: ptr = fido_assert_sig_ptr(assert, 0);
596: len = fido_assert_sig_len(assert, 0);
597: if (len != 64) {
598: skdebug(__func__, "bad length %zu", len);
599: goto out;
600: }
601: response->sig_r_len = len;
602: if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL) {
603: skdebug(__func__, "calloc signature failed");
604: goto out;
605: }
606: memcpy(response->sig_r, ptr, len);
607: ret = 0;
608: out:
609: if (ret != 0) {
610: free(response->sig_r);
611: response->sig_r = NULL;
612: }
613: return ret;
614: }
615:
616: static int
617: pack_sig(int alg, fido_assert_t *assert, struct sk_sign_response *response)
618: {
619: switch(alg) {
1.7 naddy 620: #ifdef WITH_OPENSSL
1.1 djm 621: case SK_ECDSA:
622: return pack_sig_ecdsa(assert, response);
1.7 naddy 623: #endif /* WITH_OPENSSL */
1.1 djm 624: case SK_ED25519:
625: return pack_sig_ed25519(assert, response);
626: default:
627: return -1;
628: }
629: }
630:
631: int
632: sk_sign(int alg, const uint8_t *message, size_t message_len,
633: const char *application,
634: const uint8_t *key_handle, size_t key_handle_len,
635: uint8_t flags, struct sk_sign_response **sign_response)
636: {
637: fido_assert_t *assert = NULL;
638: fido_dev_t *dev = NULL;
639: struct sk_sign_response *response = NULL;
640: int ret = -1;
641: int r;
642:
643: #ifdef SK_DEBUG
644: fido_init(FIDO_DEBUG);
645: #endif
646:
647: if (sign_response == NULL) {
648: skdebug(__func__, "sign_response == NULL");
649: goto out;
650: }
651: *sign_response = NULL;
652: if ((dev = find_device(message, message_len, application, key_handle,
653: key_handle_len)) == NULL) {
654: skdebug(__func__, "couldn't find device for key handle");
655: goto out;
656: }
657: if ((assert = fido_assert_new()) == NULL) {
658: skdebug(__func__, "fido_assert_new failed");
659: goto out;
660: }
661: if ((r = fido_assert_set_clientdata_hash(assert, message,
662: message_len)) != FIDO_OK) {
663: skdebug(__func__, "fido_assert_set_clientdata_hash: %s",
664: fido_strerr(r));
665: goto out;
666: }
667: if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK) {
668: skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r));
669: goto out;
670: }
671: if ((r = fido_assert_allow_cred(assert, key_handle,
672: key_handle_len)) != FIDO_OK) {
673: skdebug(__func__, "fido_assert_allow_cred: %s", fido_strerr(r));
674: goto out;
675: }
676: if ((r = fido_assert_set_up(assert,
677: (flags & SK_USER_PRESENCE_REQD) ?
678: FIDO_OPT_TRUE : FIDO_OPT_FALSE)) != FIDO_OK) {
679: skdebug(__func__, "fido_assert_set_up: %s", fido_strerr(r));
680: goto out;
681: }
682: if ((r = fido_dev_get_assert(dev, assert, NULL)) != FIDO_OK) {
683: skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
684: goto out;
685: }
686: if ((response = calloc(1, sizeof(*response))) == NULL) {
687: skdebug(__func__, "calloc response failed");
688: goto out;
689: }
690: response->flags = fido_assert_flags(assert, 0);
691: response->counter = fido_assert_sigcount(assert, 0);
692: if (pack_sig(alg, assert, response) != 0) {
693: skdebug(__func__, "pack_sig failed");
694: goto out;
695: }
696: *sign_response = response;
697: response = NULL;
698: ret = 0;
699: out:
700: if (response != NULL) {
701: free(response->sig_r);
702: free(response->sig_s);
703: free(response);
704: }
705: if (dev != NULL) {
706: fido_dev_close(dev);
707: fido_dev_free(&dev);
708: }
709: if (assert != NULL) {
710: fido_assert_free(&assert);
711: }
712: return ret;
713: }