10afa8e06SEd Maste /* 2*60a517b6SEd Maste * Copyright (c) 2018-2023 Yubico AB. All rights reserved. 30afa8e06SEd Maste * Use of this source code is governed by a BSD-style 40afa8e06SEd Maste * license that can be found in the LICENSE file. 52ccfa855SEd Maste * SPDX-License-Identifier: BSD-2-Clause 60afa8e06SEd Maste */ 70afa8e06SEd Maste 80afa8e06SEd Maste #include <fido.h> 90afa8e06SEd Maste #include <stdio.h> 100afa8e06SEd Maste #include <stdlib.h> 110afa8e06SEd Maste #include <string.h> 120afa8e06SEd Maste #ifdef HAVE_UNISTD_H 130afa8e06SEd Maste #include <unistd.h> 140afa8e06SEd Maste #endif 150afa8e06SEd Maste 160afa8e06SEd Maste #include "../openbsd-compat/openbsd-compat.h" 170afa8e06SEd Maste #include "extern.h" 180afa8e06SEd Maste 190afa8e06SEd Maste static fido_cred_t * 200afa8e06SEd Maste prepare_cred(FILE *in_f, int type, int flags) 210afa8e06SEd Maste { 220afa8e06SEd Maste fido_cred_t *cred = NULL; 230afa8e06SEd Maste struct blob cdh; 240afa8e06SEd Maste struct blob uid; 250afa8e06SEd Maste char *rpid = NULL; 260afa8e06SEd Maste char *uname = NULL; 270afa8e06SEd Maste int r; 280afa8e06SEd Maste 290afa8e06SEd Maste memset(&cdh, 0, sizeof(cdh)); 300afa8e06SEd Maste memset(&uid, 0, sizeof(uid)); 310afa8e06SEd Maste 320afa8e06SEd Maste r = base64_read(in_f, &cdh); 330afa8e06SEd Maste r |= string_read(in_f, &rpid); 340afa8e06SEd Maste r |= string_read(in_f, &uname); 350afa8e06SEd Maste r |= base64_read(in_f, &uid); 360afa8e06SEd Maste if (r < 0) 370afa8e06SEd Maste errx(1, "input error"); 380afa8e06SEd Maste 390afa8e06SEd Maste if (flags & FLAG_DEBUG) { 40*60a517b6SEd Maste fprintf(stderr, "client data%s:\n", 41*60a517b6SEd Maste flags & FLAG_CD ? "" : " hash"); 420afa8e06SEd Maste xxd(cdh.ptr, cdh.len); 430afa8e06SEd Maste fprintf(stderr, "relying party id: %s\n", rpid); 440afa8e06SEd Maste fprintf(stderr, "user name: %s\n", uname); 450afa8e06SEd Maste fprintf(stderr, "user id:\n"); 460afa8e06SEd Maste xxd(uid.ptr, uid.len); 470afa8e06SEd Maste } 480afa8e06SEd Maste 490afa8e06SEd Maste if ((cred = fido_cred_new()) == NULL) 500afa8e06SEd Maste errx(1, "fido_cred_new"); 510afa8e06SEd Maste 52*60a517b6SEd Maste 53*60a517b6SEd Maste if (flags & FLAG_CD) 54*60a517b6SEd Maste r = fido_cred_set_clientdata(cred, cdh.ptr, cdh.len); 55*60a517b6SEd Maste else 56*60a517b6SEd Maste r = fido_cred_set_clientdata_hash(cred, cdh.ptr, cdh.len); 57*60a517b6SEd Maste 58*60a517b6SEd Maste if (r != FIDO_OK || (r = fido_cred_set_type(cred, type)) != FIDO_OK || 590afa8e06SEd Maste (r = fido_cred_set_rp(cred, rpid, NULL)) != FIDO_OK || 600afa8e06SEd Maste (r = fido_cred_set_user(cred, uid.ptr, uid.len, uname, NULL, 610afa8e06SEd Maste NULL)) != FIDO_OK) 620afa8e06SEd Maste errx(1, "fido_cred_set: %s", fido_strerr(r)); 630afa8e06SEd Maste 640afa8e06SEd Maste if (flags & FLAG_RK) { 650afa8e06SEd Maste if ((r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK) 660afa8e06SEd Maste errx(1, "fido_cred_set_rk: %s", fido_strerr(r)); 670afa8e06SEd Maste } 680afa8e06SEd Maste if (flags & FLAG_UV) { 690afa8e06SEd Maste if ((r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) 700afa8e06SEd Maste errx(1, "fido_cred_set_uv: %s", fido_strerr(r)); 710afa8e06SEd Maste } 720afa8e06SEd Maste if (flags & FLAG_HMAC) { 730afa8e06SEd Maste if ((r = fido_cred_set_extensions(cred, 740afa8e06SEd Maste FIDO_EXT_HMAC_SECRET)) != FIDO_OK) 750afa8e06SEd Maste errx(1, "fido_cred_set_extensions: %s", fido_strerr(r)); 760afa8e06SEd Maste } 770afa8e06SEd Maste if (flags & FLAG_LARGEBLOB) { 780afa8e06SEd Maste if ((r = fido_cred_set_extensions(cred, 790afa8e06SEd Maste FIDO_EXT_LARGEBLOB_KEY)) != FIDO_OK) 800afa8e06SEd Maste errx(1, "fido_cred_set_extensions: %s", fido_strerr(r)); 810afa8e06SEd Maste } 820afa8e06SEd Maste 830afa8e06SEd Maste free(cdh.ptr); 840afa8e06SEd Maste free(uid.ptr); 850afa8e06SEd Maste free(rpid); 860afa8e06SEd Maste free(uname); 870afa8e06SEd Maste 880afa8e06SEd Maste return (cred); 890afa8e06SEd Maste } 900afa8e06SEd Maste 910afa8e06SEd Maste static void 920afa8e06SEd Maste print_attcred(FILE *out_f, const fido_cred_t *cred) 930afa8e06SEd Maste { 940afa8e06SEd Maste char *cdh = NULL; 950afa8e06SEd Maste char *authdata = NULL; 960afa8e06SEd Maste char *id = NULL; 970afa8e06SEd Maste char *sig = NULL; 980afa8e06SEd Maste char *x5c = NULL; 990afa8e06SEd Maste char *key = NULL; 1000afa8e06SEd Maste int r; 1010afa8e06SEd Maste 1020afa8e06SEd Maste r = base64_encode(fido_cred_clientdata_hash_ptr(cred), 1030afa8e06SEd Maste fido_cred_clientdata_hash_len(cred), &cdh); 1040afa8e06SEd Maste r |= base64_encode(fido_cred_authdata_ptr(cred), 1050afa8e06SEd Maste fido_cred_authdata_len(cred), &authdata); 1060afa8e06SEd Maste r |= base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), 1070afa8e06SEd Maste &id); 1080afa8e06SEd Maste r |= base64_encode(fido_cred_sig_ptr(cred), fido_cred_sig_len(cred), 1090afa8e06SEd Maste &sig); 1100afa8e06SEd Maste if (fido_cred_x5c_ptr(cred) != NULL) 1110afa8e06SEd Maste r |= base64_encode(fido_cred_x5c_ptr(cred), 1120afa8e06SEd Maste fido_cred_x5c_len(cred), &x5c); 1130afa8e06SEd Maste if (fido_cred_largeblob_key_ptr(cred) != NULL) 1140afa8e06SEd Maste r |= base64_encode(fido_cred_largeblob_key_ptr(cred), 1150afa8e06SEd Maste fido_cred_largeblob_key_len(cred), &key); 1160afa8e06SEd Maste if (r < 0) 1170afa8e06SEd Maste errx(1, "output error"); 1180afa8e06SEd Maste 1190afa8e06SEd Maste fprintf(out_f, "%s\n", cdh); 1200afa8e06SEd Maste fprintf(out_f, "%s\n", fido_cred_rp_id(cred)); 1210afa8e06SEd Maste fprintf(out_f, "%s\n", fido_cred_fmt(cred)); 1220afa8e06SEd Maste fprintf(out_f, "%s\n", authdata); 1230afa8e06SEd Maste fprintf(out_f, "%s\n", id); 1240afa8e06SEd Maste fprintf(out_f, "%s\n", sig); 1250afa8e06SEd Maste if (x5c != NULL) 1260afa8e06SEd Maste fprintf(out_f, "%s\n", x5c); 1270afa8e06SEd Maste if (key != NULL) { 1280afa8e06SEd Maste fprintf(out_f, "%s\n", key); 1290afa8e06SEd Maste explicit_bzero(key, strlen(key)); 1300afa8e06SEd Maste } 1310afa8e06SEd Maste 1320afa8e06SEd Maste free(cdh); 1330afa8e06SEd Maste free(authdata); 1340afa8e06SEd Maste free(id); 1350afa8e06SEd Maste free(sig); 1360afa8e06SEd Maste free(x5c); 1370afa8e06SEd Maste free(key); 1380afa8e06SEd Maste } 1390afa8e06SEd Maste 1400afa8e06SEd Maste int 1410afa8e06SEd Maste cred_make(int argc, char **argv) 1420afa8e06SEd Maste { 1430afa8e06SEd Maste fido_dev_t *dev = NULL; 1440afa8e06SEd Maste fido_cred_t *cred = NULL; 1450afa8e06SEd Maste char prompt[1024]; 1462ccfa855SEd Maste char pin[128]; 1470afa8e06SEd Maste char *in_path = NULL; 1480afa8e06SEd Maste char *out_path = NULL; 1490afa8e06SEd Maste FILE *in_f = NULL; 1500afa8e06SEd Maste FILE *out_f = NULL; 1510afa8e06SEd Maste int type = COSE_ES256; 1520afa8e06SEd Maste int flags = 0; 1530afa8e06SEd Maste int cred_protect = -1; 1540afa8e06SEd Maste int ch; 1550afa8e06SEd Maste int r; 1560afa8e06SEd Maste 157*60a517b6SEd Maste while ((ch = getopt(argc, argv, "bc:dhi:o:qruvw")) != -1) { 1580afa8e06SEd Maste switch (ch) { 1590afa8e06SEd Maste case 'b': 1600afa8e06SEd Maste flags |= FLAG_LARGEBLOB; 1610afa8e06SEd Maste break; 1620afa8e06SEd Maste case 'c': 1630afa8e06SEd Maste if ((cred_protect = base10(optarg)) < 0) 1640afa8e06SEd Maste errx(1, "-c: invalid argument '%s'", optarg); 1650afa8e06SEd Maste break; 1660afa8e06SEd Maste case 'd': 1670afa8e06SEd Maste flags |= FLAG_DEBUG; 1680afa8e06SEd Maste break; 1690afa8e06SEd Maste case 'h': 1700afa8e06SEd Maste flags |= FLAG_HMAC; 1710afa8e06SEd Maste break; 1720afa8e06SEd Maste case 'i': 1730afa8e06SEd Maste in_path = optarg; 1740afa8e06SEd Maste break; 1750afa8e06SEd Maste case 'o': 1760afa8e06SEd Maste out_path = optarg; 1770afa8e06SEd Maste break; 1780afa8e06SEd Maste case 'q': 1790afa8e06SEd Maste flags |= FLAG_QUIET; 1800afa8e06SEd Maste break; 1810afa8e06SEd Maste case 'r': 1820afa8e06SEd Maste flags |= FLAG_RK; 1830afa8e06SEd Maste break; 1840afa8e06SEd Maste case 'u': 1850afa8e06SEd Maste flags |= FLAG_U2F; 1860afa8e06SEd Maste break; 1870afa8e06SEd Maste case 'v': 1880afa8e06SEd Maste flags |= FLAG_UV; 1890afa8e06SEd Maste break; 190*60a517b6SEd Maste case 'w': 191*60a517b6SEd Maste flags |= FLAG_CD; 192*60a517b6SEd Maste break; 1930afa8e06SEd Maste default: 1940afa8e06SEd Maste usage(); 1950afa8e06SEd Maste } 1960afa8e06SEd Maste } 1970afa8e06SEd Maste 1980afa8e06SEd Maste argc -= optind; 1990afa8e06SEd Maste argv += optind; 2000afa8e06SEd Maste 2010afa8e06SEd Maste if (argc < 1 || argc > 2) 2020afa8e06SEd Maste usage(); 2030afa8e06SEd Maste 2040afa8e06SEd Maste in_f = open_read(in_path); 2050afa8e06SEd Maste out_f = open_write(out_path); 2060afa8e06SEd Maste 2070afa8e06SEd Maste if (argc > 1 && cose_type(argv[1], &type) < 0) 2080afa8e06SEd Maste errx(1, "unknown type %s", argv[1]); 2090afa8e06SEd Maste 2100afa8e06SEd Maste fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); 2110afa8e06SEd Maste 2120afa8e06SEd Maste cred = prepare_cred(in_f, type, flags); 2130afa8e06SEd Maste 2140afa8e06SEd Maste dev = open_dev(argv[0]); 2150afa8e06SEd Maste if (flags & FLAG_U2F) 2160afa8e06SEd Maste fido_dev_force_u2f(dev); 2170afa8e06SEd Maste 2180afa8e06SEd Maste if (cred_protect > 0) { 2190afa8e06SEd Maste r = fido_cred_set_prot(cred, cred_protect); 2200afa8e06SEd Maste if (r != FIDO_OK) { 2210afa8e06SEd Maste errx(1, "fido_cred_set_prot: %s", fido_strerr(r)); 2220afa8e06SEd Maste } 2230afa8e06SEd Maste } 2240afa8e06SEd Maste 2250afa8e06SEd Maste r = fido_dev_make_cred(dev, cred, NULL); 2260afa8e06SEd Maste if (r == FIDO_ERR_PIN_REQUIRED && !(flags & FLAG_QUIET)) { 2270afa8e06SEd Maste r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", 2280afa8e06SEd Maste argv[0]); 2290afa8e06SEd Maste if (r < 0 || (size_t)r >= sizeof(prompt)) 2300afa8e06SEd Maste errx(1, "snprintf"); 2310afa8e06SEd Maste if (!readpassphrase(prompt, pin, sizeof(pin), RPP_ECHO_OFF)) 2320afa8e06SEd Maste errx(1, "readpassphrase"); 2332ccfa855SEd Maste if (strlen(pin) < 4 || strlen(pin) > 63) { 2342ccfa855SEd Maste explicit_bzero(pin, sizeof(pin)); 2352ccfa855SEd Maste errx(1, "invalid PIN length"); 2362ccfa855SEd Maste } 2370afa8e06SEd Maste r = fido_dev_make_cred(dev, cred, pin); 2380afa8e06SEd Maste } 2390afa8e06SEd Maste 2400afa8e06SEd Maste explicit_bzero(pin, sizeof(pin)); 2410afa8e06SEd Maste if (r != FIDO_OK) 2420afa8e06SEd Maste errx(1, "fido_dev_make_cred: %s", fido_strerr(r)); 2430afa8e06SEd Maste print_attcred(out_f, cred); 2440afa8e06SEd Maste 2450afa8e06SEd Maste fido_dev_close(dev); 2460afa8e06SEd Maste fido_dev_free(&dev); 2470afa8e06SEd Maste fido_cred_free(&cred); 2480afa8e06SEd Maste 2490afa8e06SEd Maste fclose(in_f); 2500afa8e06SEd Maste fclose(out_f); 2510afa8e06SEd Maste in_f = NULL; 2520afa8e06SEd Maste out_f = NULL; 2530afa8e06SEd Maste 2540afa8e06SEd Maste exit(0); 2550afa8e06SEd Maste } 256