Annotation of src/usr.bin/ssh/sk-usbhid.c, Revision 1.1
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);
! 112: debug("%s: %s", __func__, msg);
! 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: }