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