1*0afa8e06SEd Maste /* 2*0afa8e06SEd Maste * Copyright (c) 2018 Yubico AB. All rights reserved. 3*0afa8e06SEd Maste * Use of this source code is governed by a BSD-style 4*0afa8e06SEd Maste * license that can be found in the LICENSE file. 5*0afa8e06SEd Maste */ 6*0afa8e06SEd Maste 7*0afa8e06SEd Maste #include <fido.h> 8*0afa8e06SEd Maste #include <stdio.h> 9*0afa8e06SEd Maste #include <stdlib.h> 10*0afa8e06SEd Maste #include <string.h> 11*0afa8e06SEd Maste #ifdef HAVE_UNISTD_H 12*0afa8e06SEd Maste #include <unistd.h> 13*0afa8e06SEd Maste #endif 14*0afa8e06SEd Maste 15*0afa8e06SEd Maste #include "../openbsd-compat/openbsd-compat.h" 16*0afa8e06SEd Maste #include "extern.h" 17*0afa8e06SEd Maste 18*0afa8e06SEd Maste struct toggle { 19*0afa8e06SEd Maste fido_opt_t up; 20*0afa8e06SEd Maste fido_opt_t uv; 21*0afa8e06SEd Maste fido_opt_t pin; 22*0afa8e06SEd Maste }; 23*0afa8e06SEd Maste 24*0afa8e06SEd Maste static const char * 25*0afa8e06SEd Maste opt2str(fido_opt_t v) 26*0afa8e06SEd Maste { 27*0afa8e06SEd Maste switch (v) { 28*0afa8e06SEd Maste case FIDO_OPT_OMIT: 29*0afa8e06SEd Maste return "omit"; 30*0afa8e06SEd Maste case FIDO_OPT_TRUE: 31*0afa8e06SEd Maste return "true"; 32*0afa8e06SEd Maste case FIDO_OPT_FALSE: 33*0afa8e06SEd Maste return "false"; 34*0afa8e06SEd Maste default: 35*0afa8e06SEd Maste return "unknown"; 36*0afa8e06SEd Maste } 37*0afa8e06SEd Maste } 38*0afa8e06SEd Maste 39*0afa8e06SEd Maste static void 40*0afa8e06SEd Maste parse_toggle(const char *str, struct toggle *opt) 41*0afa8e06SEd Maste { 42*0afa8e06SEd Maste fido_opt_t *k; 43*0afa8e06SEd Maste fido_opt_t v; 44*0afa8e06SEd Maste char *assignment; 45*0afa8e06SEd Maste char *key; 46*0afa8e06SEd Maste char *val; 47*0afa8e06SEd Maste 48*0afa8e06SEd Maste if ((assignment = strdup(str)) == NULL) 49*0afa8e06SEd Maste err(1, "strdup"); 50*0afa8e06SEd Maste if ((val = strchr(assignment, '=')) == NULL) 51*0afa8e06SEd Maste errx(1, "invalid assignment '%s'", assignment); 52*0afa8e06SEd Maste 53*0afa8e06SEd Maste key = assignment; 54*0afa8e06SEd Maste *val++ = '\0'; 55*0afa8e06SEd Maste 56*0afa8e06SEd Maste if (!strcmp(val, "true")) 57*0afa8e06SEd Maste v = FIDO_OPT_TRUE; 58*0afa8e06SEd Maste else if (!strcmp(val, "false")) 59*0afa8e06SEd Maste v = FIDO_OPT_FALSE; 60*0afa8e06SEd Maste else 61*0afa8e06SEd Maste errx(1, "unknown value '%s'", val); 62*0afa8e06SEd Maste 63*0afa8e06SEd Maste if (!strcmp(key, "up")) 64*0afa8e06SEd Maste k = &opt->up; 65*0afa8e06SEd Maste else if (!strcmp(key, "uv")) 66*0afa8e06SEd Maste k = &opt->uv; 67*0afa8e06SEd Maste else if (!strcmp(key, "pin")) 68*0afa8e06SEd Maste k = &opt->pin; 69*0afa8e06SEd Maste else 70*0afa8e06SEd Maste errx(1, "unknown key '%s'", key); 71*0afa8e06SEd Maste 72*0afa8e06SEd Maste free(assignment); 73*0afa8e06SEd Maste 74*0afa8e06SEd Maste *k = v; 75*0afa8e06SEd Maste } 76*0afa8e06SEd Maste 77*0afa8e06SEd Maste static fido_assert_t * 78*0afa8e06SEd Maste prepare_assert(FILE *in_f, int flags, const struct toggle *opt) 79*0afa8e06SEd Maste { 80*0afa8e06SEd Maste fido_assert_t *assert = NULL; 81*0afa8e06SEd Maste struct blob cdh; 82*0afa8e06SEd Maste struct blob id; 83*0afa8e06SEd Maste struct blob hmac_salt; 84*0afa8e06SEd Maste char *rpid = NULL; 85*0afa8e06SEd Maste int r; 86*0afa8e06SEd Maste 87*0afa8e06SEd Maste memset(&cdh, 0, sizeof(cdh)); 88*0afa8e06SEd Maste memset(&id, 0, sizeof(id)); 89*0afa8e06SEd Maste memset(&hmac_salt, 0, sizeof(hmac_salt)); 90*0afa8e06SEd Maste 91*0afa8e06SEd Maste r = base64_read(in_f, &cdh); 92*0afa8e06SEd Maste r |= string_read(in_f, &rpid); 93*0afa8e06SEd Maste if ((flags & FLAG_RK) == 0) 94*0afa8e06SEd Maste r |= base64_read(in_f, &id); 95*0afa8e06SEd Maste if (flags & FLAG_HMAC) 96*0afa8e06SEd Maste r |= base64_read(in_f, &hmac_salt); 97*0afa8e06SEd Maste if (r < 0) 98*0afa8e06SEd Maste errx(1, "input error"); 99*0afa8e06SEd Maste 100*0afa8e06SEd Maste if (flags & FLAG_DEBUG) { 101*0afa8e06SEd Maste fprintf(stderr, "client data hash:\n"); 102*0afa8e06SEd Maste xxd(cdh.ptr, cdh.len); 103*0afa8e06SEd Maste fprintf(stderr, "relying party id: %s\n", rpid); 104*0afa8e06SEd Maste if ((flags & FLAG_RK) == 0) { 105*0afa8e06SEd Maste fprintf(stderr, "credential id:\n"); 106*0afa8e06SEd Maste xxd(id.ptr, id.len); 107*0afa8e06SEd Maste } 108*0afa8e06SEd Maste fprintf(stderr, "up=%s\n", opt2str(opt->up)); 109*0afa8e06SEd Maste fprintf(stderr, "uv=%s\n", opt2str(opt->uv)); 110*0afa8e06SEd Maste fprintf(stderr, "pin=%s\n", opt2str(opt->pin)); 111*0afa8e06SEd Maste } 112*0afa8e06SEd Maste 113*0afa8e06SEd Maste if ((assert = fido_assert_new()) == NULL) 114*0afa8e06SEd Maste errx(1, "fido_assert_new"); 115*0afa8e06SEd Maste 116*0afa8e06SEd Maste if ((r = fido_assert_set_clientdata_hash(assert, cdh.ptr, 117*0afa8e06SEd Maste cdh.len)) != FIDO_OK || 118*0afa8e06SEd Maste (r = fido_assert_set_rp(assert, rpid)) != FIDO_OK) 119*0afa8e06SEd Maste errx(1, "fido_assert_set: %s", fido_strerr(r)); 120*0afa8e06SEd Maste if ((r = fido_assert_set_up(assert, opt->up)) != FIDO_OK) 121*0afa8e06SEd Maste errx(1, "fido_assert_set_up: %s", fido_strerr(r)); 122*0afa8e06SEd Maste if ((r = fido_assert_set_uv(assert, opt->uv)) != FIDO_OK) 123*0afa8e06SEd Maste errx(1, "fido_assert_set_uv: %s", fido_strerr(r)); 124*0afa8e06SEd Maste 125*0afa8e06SEd Maste if (flags & FLAG_HMAC) { 126*0afa8e06SEd Maste if ((r = fido_assert_set_extensions(assert, 127*0afa8e06SEd Maste FIDO_EXT_HMAC_SECRET)) != FIDO_OK) 128*0afa8e06SEd Maste errx(1, "fido_assert_set_extensions: %s", 129*0afa8e06SEd Maste fido_strerr(r)); 130*0afa8e06SEd Maste if ((r = fido_assert_set_hmac_salt(assert, hmac_salt.ptr, 131*0afa8e06SEd Maste hmac_salt.len)) != FIDO_OK) 132*0afa8e06SEd Maste errx(1, "fido_assert_set_hmac_salt: %s", 133*0afa8e06SEd Maste fido_strerr(r)); 134*0afa8e06SEd Maste } 135*0afa8e06SEd Maste if (flags & FLAG_LARGEBLOB) { 136*0afa8e06SEd Maste if ((r = fido_assert_set_extensions(assert, 137*0afa8e06SEd Maste FIDO_EXT_LARGEBLOB_KEY)) != FIDO_OK) 138*0afa8e06SEd Maste errx(1, "fido_assert_set_extensions: %s", fido_strerr(r)); 139*0afa8e06SEd Maste } 140*0afa8e06SEd Maste if ((flags & FLAG_RK) == 0) { 141*0afa8e06SEd Maste if ((r = fido_assert_allow_cred(assert, id.ptr, 142*0afa8e06SEd Maste id.len)) != FIDO_OK) 143*0afa8e06SEd Maste errx(1, "fido_assert_allow_cred: %s", fido_strerr(r)); 144*0afa8e06SEd Maste } 145*0afa8e06SEd Maste 146*0afa8e06SEd Maste free(hmac_salt.ptr); 147*0afa8e06SEd Maste free(cdh.ptr); 148*0afa8e06SEd Maste free(id.ptr); 149*0afa8e06SEd Maste free(rpid); 150*0afa8e06SEd Maste 151*0afa8e06SEd Maste return (assert); 152*0afa8e06SEd Maste } 153*0afa8e06SEd Maste 154*0afa8e06SEd Maste static void 155*0afa8e06SEd Maste print_assert(FILE *out_f, const fido_assert_t *assert, size_t idx, int flags) 156*0afa8e06SEd Maste { 157*0afa8e06SEd Maste char *cdh = NULL; 158*0afa8e06SEd Maste char *authdata = NULL; 159*0afa8e06SEd Maste char *sig = NULL; 160*0afa8e06SEd Maste char *user_id = NULL; 161*0afa8e06SEd Maste char *hmac_secret = NULL; 162*0afa8e06SEd Maste char *key = NULL; 163*0afa8e06SEd Maste int r; 164*0afa8e06SEd Maste 165*0afa8e06SEd Maste r = base64_encode(fido_assert_clientdata_hash_ptr(assert), 166*0afa8e06SEd Maste fido_assert_clientdata_hash_len(assert), &cdh); 167*0afa8e06SEd Maste r |= base64_encode(fido_assert_authdata_ptr(assert, idx), 168*0afa8e06SEd Maste fido_assert_authdata_len(assert, 0), &authdata); 169*0afa8e06SEd Maste r |= base64_encode(fido_assert_sig_ptr(assert, idx), 170*0afa8e06SEd Maste fido_assert_sig_len(assert, idx), &sig); 171*0afa8e06SEd Maste if (flags & FLAG_RK) 172*0afa8e06SEd Maste r |= base64_encode(fido_assert_user_id_ptr(assert, idx), 173*0afa8e06SEd Maste fido_assert_user_id_len(assert, idx), &user_id); 174*0afa8e06SEd Maste if (flags & FLAG_HMAC) 175*0afa8e06SEd Maste r |= base64_encode(fido_assert_hmac_secret_ptr(assert, idx), 176*0afa8e06SEd Maste fido_assert_hmac_secret_len(assert, idx), &hmac_secret); 177*0afa8e06SEd Maste if (flags & FLAG_LARGEBLOB) 178*0afa8e06SEd Maste r |= base64_encode(fido_assert_largeblob_key_ptr(assert, idx), 179*0afa8e06SEd Maste fido_assert_largeblob_key_len(assert, idx), &key); 180*0afa8e06SEd Maste if (r < 0) 181*0afa8e06SEd Maste errx(1, "output error"); 182*0afa8e06SEd Maste 183*0afa8e06SEd Maste fprintf(out_f, "%s\n", cdh); 184*0afa8e06SEd Maste fprintf(out_f, "%s\n", fido_assert_rp_id(assert)); 185*0afa8e06SEd Maste fprintf(out_f, "%s\n", authdata); 186*0afa8e06SEd Maste fprintf(out_f, "%s\n", sig); 187*0afa8e06SEd Maste if (flags & FLAG_RK) 188*0afa8e06SEd Maste fprintf(out_f, "%s\n", user_id); 189*0afa8e06SEd Maste if (hmac_secret) { 190*0afa8e06SEd Maste fprintf(out_f, "%s\n", hmac_secret); 191*0afa8e06SEd Maste explicit_bzero(hmac_secret, strlen(hmac_secret)); 192*0afa8e06SEd Maste } 193*0afa8e06SEd Maste if (key) { 194*0afa8e06SEd Maste fprintf(out_f, "%s\n", key); 195*0afa8e06SEd Maste explicit_bzero(key, strlen(key)); 196*0afa8e06SEd Maste } 197*0afa8e06SEd Maste 198*0afa8e06SEd Maste free(key); 199*0afa8e06SEd Maste free(hmac_secret); 200*0afa8e06SEd Maste free(cdh); 201*0afa8e06SEd Maste free(authdata); 202*0afa8e06SEd Maste free(sig); 203*0afa8e06SEd Maste free(user_id); 204*0afa8e06SEd Maste } 205*0afa8e06SEd Maste 206*0afa8e06SEd Maste int 207*0afa8e06SEd Maste assert_get(int argc, char **argv) 208*0afa8e06SEd Maste { 209*0afa8e06SEd Maste fido_dev_t *dev = NULL; 210*0afa8e06SEd Maste fido_assert_t *assert = NULL; 211*0afa8e06SEd Maste struct toggle opt; 212*0afa8e06SEd Maste char pin[1024]; 213*0afa8e06SEd Maste char prompt[1024]; 214*0afa8e06SEd Maste char *in_path = NULL; 215*0afa8e06SEd Maste char *out_path = NULL; 216*0afa8e06SEd Maste FILE *in_f = NULL; 217*0afa8e06SEd Maste FILE *out_f = NULL; 218*0afa8e06SEd Maste int flags = 0; 219*0afa8e06SEd Maste int ch; 220*0afa8e06SEd Maste int r; 221*0afa8e06SEd Maste 222*0afa8e06SEd Maste opt.up = opt.uv = opt.pin = FIDO_OPT_OMIT; 223*0afa8e06SEd Maste 224*0afa8e06SEd Maste while ((ch = getopt(argc, argv, "bdhi:o:prt:uv")) != -1) { 225*0afa8e06SEd Maste switch (ch) { 226*0afa8e06SEd Maste case 'b': 227*0afa8e06SEd Maste flags |= FLAG_LARGEBLOB; 228*0afa8e06SEd Maste break; 229*0afa8e06SEd Maste case 'd': 230*0afa8e06SEd Maste flags |= FLAG_DEBUG; 231*0afa8e06SEd Maste break; 232*0afa8e06SEd Maste case 'h': 233*0afa8e06SEd Maste flags |= FLAG_HMAC; 234*0afa8e06SEd Maste break; 235*0afa8e06SEd Maste case 'i': 236*0afa8e06SEd Maste in_path = optarg; 237*0afa8e06SEd Maste break; 238*0afa8e06SEd Maste case 'o': 239*0afa8e06SEd Maste out_path = optarg; 240*0afa8e06SEd Maste break; 241*0afa8e06SEd Maste case 'p': 242*0afa8e06SEd Maste opt.up = FIDO_OPT_TRUE; 243*0afa8e06SEd Maste break; 244*0afa8e06SEd Maste case 'r': 245*0afa8e06SEd Maste flags |= FLAG_RK; 246*0afa8e06SEd Maste break; 247*0afa8e06SEd Maste case 't' : 248*0afa8e06SEd Maste parse_toggle(optarg, &opt); 249*0afa8e06SEd Maste break; 250*0afa8e06SEd Maste case 'u': 251*0afa8e06SEd Maste flags |= FLAG_U2F; 252*0afa8e06SEd Maste break; 253*0afa8e06SEd Maste case 'v': 254*0afa8e06SEd Maste /* -v implies both pin and uv for historical reasons */ 255*0afa8e06SEd Maste opt.pin = FIDO_OPT_TRUE; 256*0afa8e06SEd Maste opt.uv = FIDO_OPT_TRUE; 257*0afa8e06SEd Maste break; 258*0afa8e06SEd Maste default: 259*0afa8e06SEd Maste usage(); 260*0afa8e06SEd Maste } 261*0afa8e06SEd Maste } 262*0afa8e06SEd Maste 263*0afa8e06SEd Maste argc -= optind; 264*0afa8e06SEd Maste argv += optind; 265*0afa8e06SEd Maste 266*0afa8e06SEd Maste if (argc < 1) 267*0afa8e06SEd Maste usage(); 268*0afa8e06SEd Maste 269*0afa8e06SEd Maste in_f = open_read(in_path); 270*0afa8e06SEd Maste out_f = open_write(out_path); 271*0afa8e06SEd Maste 272*0afa8e06SEd Maste fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); 273*0afa8e06SEd Maste 274*0afa8e06SEd Maste assert = prepare_assert(in_f, flags, &opt); 275*0afa8e06SEd Maste 276*0afa8e06SEd Maste dev = open_dev(argv[0]); 277*0afa8e06SEd Maste if (flags & FLAG_U2F) 278*0afa8e06SEd Maste fido_dev_force_u2f(dev); 279*0afa8e06SEd Maste 280*0afa8e06SEd Maste if (opt.pin == FIDO_OPT_TRUE) { 281*0afa8e06SEd Maste r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", 282*0afa8e06SEd Maste argv[0]); 283*0afa8e06SEd Maste if (r < 0 || (size_t)r >= sizeof(prompt)) 284*0afa8e06SEd Maste errx(1, "snprintf"); 285*0afa8e06SEd Maste if (!readpassphrase(prompt, pin, sizeof(pin), RPP_ECHO_OFF)) 286*0afa8e06SEd Maste errx(1, "readpassphrase"); 287*0afa8e06SEd Maste r = fido_dev_get_assert(dev, assert, pin); 288*0afa8e06SEd Maste } else 289*0afa8e06SEd Maste r = fido_dev_get_assert(dev, assert, NULL); 290*0afa8e06SEd Maste 291*0afa8e06SEd Maste explicit_bzero(pin, sizeof(pin)); 292*0afa8e06SEd Maste 293*0afa8e06SEd Maste if (r != FIDO_OK) 294*0afa8e06SEd Maste errx(1, "fido_dev_get_assert: %s", fido_strerr(r)); 295*0afa8e06SEd Maste 296*0afa8e06SEd Maste if (flags & FLAG_RK) { 297*0afa8e06SEd Maste for (size_t idx = 0; idx < fido_assert_count(assert); idx++) 298*0afa8e06SEd Maste print_assert(out_f, assert, idx, flags); 299*0afa8e06SEd Maste } else { 300*0afa8e06SEd Maste if (fido_assert_count(assert) != 1) 301*0afa8e06SEd Maste errx(1, "fido_assert_count: %zu", 302*0afa8e06SEd Maste fido_assert_count(assert)); 303*0afa8e06SEd Maste print_assert(out_f, assert, 0, flags); 304*0afa8e06SEd Maste } 305*0afa8e06SEd Maste 306*0afa8e06SEd Maste fido_dev_close(dev); 307*0afa8e06SEd Maste fido_dev_free(&dev); 308*0afa8e06SEd Maste fido_assert_free(&assert); 309*0afa8e06SEd Maste 310*0afa8e06SEd Maste fclose(in_f); 311*0afa8e06SEd Maste fclose(out_f); 312*0afa8e06SEd Maste in_f = NULL; 313*0afa8e06SEd Maste out_f = NULL; 314*0afa8e06SEd Maste 315*0afa8e06SEd Maste exit(0); 316*0afa8e06SEd Maste } 317