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