xref: /freebsd-src/contrib/libfido2/tools/token.c (revision f540a43052c12c76d3453ead881248d5467a1ab0)
10afa8e06SEd Maste /*
20afa8e06SEd Maste  * Copyright (c) 2018 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.
50afa8e06SEd Maste  */
60afa8e06SEd Maste 
70afa8e06SEd Maste #include <fido.h>
80afa8e06SEd Maste #include <stdbool.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 void
200afa8e06SEd Maste format_flags(char *ret, size_t retlen, uint8_t flags)
210afa8e06SEd Maste {
220afa8e06SEd Maste 	memset(ret, 0, retlen);
230afa8e06SEd Maste 
240afa8e06SEd Maste 	if (flags & FIDO_CAP_WINK) {
250afa8e06SEd Maste 		if (strlcat(ret, "wink,", retlen) >= retlen)
260afa8e06SEd Maste 			goto toolong;
270afa8e06SEd Maste 	} else {
280afa8e06SEd Maste 		if (strlcat(ret, "nowink,", retlen) >= retlen)
290afa8e06SEd Maste 			goto toolong;
300afa8e06SEd Maste 	}
310afa8e06SEd Maste 
320afa8e06SEd Maste 	if (flags & FIDO_CAP_CBOR) {
330afa8e06SEd Maste 		if (strlcat(ret, " cbor,", retlen) >= retlen)
340afa8e06SEd Maste 			goto toolong;
350afa8e06SEd Maste 	} else {
360afa8e06SEd Maste 		if (strlcat(ret, " nocbor,", retlen) >= retlen)
370afa8e06SEd Maste 			goto toolong;
380afa8e06SEd Maste 	}
390afa8e06SEd Maste 
400afa8e06SEd Maste 	if (flags & FIDO_CAP_NMSG) {
410afa8e06SEd Maste 		if (strlcat(ret, " nomsg", retlen) >= retlen)
420afa8e06SEd Maste 			goto toolong;
430afa8e06SEd Maste 	} else {
440afa8e06SEd Maste 		if (strlcat(ret, " msg", retlen) >= retlen)
450afa8e06SEd Maste 			goto toolong;
460afa8e06SEd Maste 	}
470afa8e06SEd Maste 
480afa8e06SEd Maste 	return;
490afa8e06SEd Maste toolong:
500afa8e06SEd Maste 	strlcpy(ret, "toolong", retlen);
510afa8e06SEd Maste }
520afa8e06SEd Maste 
530afa8e06SEd Maste static void
540afa8e06SEd Maste print_attr(const fido_dev_t *dev)
550afa8e06SEd Maste {
560afa8e06SEd Maste 	char flags_txt[128];
570afa8e06SEd Maste 
580afa8e06SEd Maste 	printf("proto: 0x%02x\n", fido_dev_protocol(dev));
590afa8e06SEd Maste 	printf("major: 0x%02x\n", fido_dev_major(dev));
600afa8e06SEd Maste 	printf("minor: 0x%02x\n", fido_dev_minor(dev));
610afa8e06SEd Maste 	printf("build: 0x%02x\n", fido_dev_build(dev));
620afa8e06SEd Maste 
630afa8e06SEd Maste 	format_flags(flags_txt, sizeof(flags_txt), fido_dev_flags(dev));
640afa8e06SEd Maste 	printf("caps: 0x%02x (%s)\n", fido_dev_flags(dev), flags_txt);
650afa8e06SEd Maste }
660afa8e06SEd Maste 
670afa8e06SEd Maste static void
680afa8e06SEd Maste print_str_array(const char *label, char * const *sa, size_t len)
690afa8e06SEd Maste {
700afa8e06SEd Maste 	if (len == 0)
710afa8e06SEd Maste 		return;
720afa8e06SEd Maste 
730afa8e06SEd Maste 	printf("%s strings: ", label);
740afa8e06SEd Maste 
750afa8e06SEd Maste 	for (size_t i = 0; i < len; i++)
760afa8e06SEd Maste 		printf("%s%s", i > 0 ? ", " : "", sa[i]);
770afa8e06SEd Maste 
780afa8e06SEd Maste 	printf("\n");
790afa8e06SEd Maste }
800afa8e06SEd Maste 
810afa8e06SEd Maste static void
820afa8e06SEd Maste print_opt_array(const char *label, char * const *name, const bool *value,
830afa8e06SEd Maste     size_t len)
840afa8e06SEd Maste {
850afa8e06SEd Maste 	if (len == 0)
860afa8e06SEd Maste 		return;
870afa8e06SEd Maste 
880afa8e06SEd Maste 	printf("%s: ", label);
890afa8e06SEd Maste 
900afa8e06SEd Maste 	for (size_t i = 0; i < len; i++)
910afa8e06SEd Maste 		printf("%s%s%s", i > 0 ? ", " : "",
920afa8e06SEd Maste 		    value[i] ? "" : "no", name[i]);
930afa8e06SEd Maste 
940afa8e06SEd Maste 	printf("\n");
950afa8e06SEd Maste }
960afa8e06SEd Maste 
970afa8e06SEd Maste static void
980afa8e06SEd Maste print_algorithms(const fido_cbor_info_t *ci)
990afa8e06SEd Maste {
1000afa8e06SEd Maste 	const char *cose, *type;
1010afa8e06SEd Maste 	size_t len;
1020afa8e06SEd Maste 
1030afa8e06SEd Maste 	if ((len = fido_cbor_info_algorithm_count(ci)) == 0)
1040afa8e06SEd Maste 		return;
1050afa8e06SEd Maste 
1060afa8e06SEd Maste 	printf("algorithms: ");
1070afa8e06SEd Maste 
1080afa8e06SEd Maste 	for (size_t i = 0; i < len; i++) {
1090afa8e06SEd Maste 		cose = type = "unknown";
1100afa8e06SEd Maste 		switch (fido_cbor_info_algorithm_cose(ci, i)) {
1110afa8e06SEd Maste 		case COSE_EDDSA:
1120afa8e06SEd Maste 			cose = "eddsa";
1130afa8e06SEd Maste 			break;
1140afa8e06SEd Maste 		case COSE_ES256:
1150afa8e06SEd Maste 			cose = "es256";
1160afa8e06SEd Maste 			break;
1170afa8e06SEd Maste 		case COSE_RS256:
1180afa8e06SEd Maste 			cose = "rs256";
1190afa8e06SEd Maste 			break;
1200afa8e06SEd Maste 		}
1210afa8e06SEd Maste 		if (fido_cbor_info_algorithm_type(ci, i) != NULL)
1220afa8e06SEd Maste 			type = fido_cbor_info_algorithm_type(ci, i);
1230afa8e06SEd Maste 		printf("%s%s (%s)", i > 0 ? ", " : "", cose, type);
1240afa8e06SEd Maste 	}
1250afa8e06SEd Maste 
1260afa8e06SEd Maste 	printf("\n");
1270afa8e06SEd Maste }
1280afa8e06SEd Maste 
1290afa8e06SEd Maste static void
1300afa8e06SEd Maste print_aaguid(const unsigned char *buf, size_t buflen)
1310afa8e06SEd Maste {
1320afa8e06SEd Maste 	printf("aaguid: ");
1330afa8e06SEd Maste 
1340afa8e06SEd Maste 	while (buflen--)
1350afa8e06SEd Maste 		printf("%02x", *buf++);
1360afa8e06SEd Maste 
1370afa8e06SEd Maste 	printf("\n");
1380afa8e06SEd Maste }
1390afa8e06SEd Maste 
1400afa8e06SEd Maste static void
1410afa8e06SEd Maste print_maxmsgsiz(uint64_t maxmsgsiz)
1420afa8e06SEd Maste {
1430afa8e06SEd Maste 	printf("maxmsgsiz: %d\n", (int)maxmsgsiz);
1440afa8e06SEd Maste }
1450afa8e06SEd Maste 
1460afa8e06SEd Maste static void
1470afa8e06SEd Maste print_maxcredcntlst(uint64_t maxcredcntlst)
1480afa8e06SEd Maste {
1490afa8e06SEd Maste 	printf("maxcredcntlst: %d\n", (int)maxcredcntlst);
1500afa8e06SEd Maste }
1510afa8e06SEd Maste 
1520afa8e06SEd Maste static void
1530afa8e06SEd Maste print_maxcredidlen(uint64_t maxcredidlen)
1540afa8e06SEd Maste {
1550afa8e06SEd Maste 	printf("maxcredlen: %d\n", (int)maxcredidlen);
1560afa8e06SEd Maste }
1570afa8e06SEd Maste 
1580afa8e06SEd Maste static void
1590afa8e06SEd Maste print_fwversion(uint64_t fwversion)
1600afa8e06SEd Maste {
1610afa8e06SEd Maste 	printf("fwversion: 0x%x\n", (int)fwversion);
1620afa8e06SEd Maste }
1630afa8e06SEd Maste 
1640afa8e06SEd Maste static void
1650afa8e06SEd Maste print_byte_array(const char *label, const uint8_t *ba, size_t len)
1660afa8e06SEd Maste {
1670afa8e06SEd Maste 	if (len == 0)
1680afa8e06SEd Maste 		return;
1690afa8e06SEd Maste 
1700afa8e06SEd Maste 	printf("%s: ", label);
1710afa8e06SEd Maste 
1720afa8e06SEd Maste 	for (size_t i = 0; i < len; i++)
1730afa8e06SEd Maste 		printf("%s%u", i > 0 ? ", " : "", (unsigned)ba[i]);
1740afa8e06SEd Maste 
1750afa8e06SEd Maste 	printf("\n");
1760afa8e06SEd Maste }
1770afa8e06SEd Maste 
1780afa8e06SEd Maste int
1790afa8e06SEd Maste token_info(int argc, char **argv, char *path)
1800afa8e06SEd Maste {
1810afa8e06SEd Maste 	char			*cred_id = NULL;
1820afa8e06SEd Maste 	char			*rp_id = NULL;
1830afa8e06SEd Maste 	fido_cbor_info_t	*ci = NULL;
1840afa8e06SEd Maste 	fido_dev_t		*dev = NULL;
1850afa8e06SEd Maste 	int			 ch;
1860afa8e06SEd Maste 	int			 credman = 0;
1870afa8e06SEd Maste 	int			 r;
1880afa8e06SEd Maste 	int			 retrycnt;
1890afa8e06SEd Maste 
1900afa8e06SEd Maste 	optind = 1;
1910afa8e06SEd Maste 
1920afa8e06SEd Maste 	while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
1930afa8e06SEd Maste 		switch (ch) {
1940afa8e06SEd Maste 		case 'c':
1950afa8e06SEd Maste 			credman = 1;
1960afa8e06SEd Maste 			break;
1970afa8e06SEd Maste 		case 'i':
1980afa8e06SEd Maste 			cred_id = optarg;
1990afa8e06SEd Maste 			break;
2000afa8e06SEd Maste 		case 'k':
2010afa8e06SEd Maste 			rp_id = optarg;
2020afa8e06SEd Maste 			break;
2030afa8e06SEd Maste 		default:
2040afa8e06SEd Maste 			break; /* ignore */
2050afa8e06SEd Maste 		}
2060afa8e06SEd Maste 	}
2070afa8e06SEd Maste 
2080afa8e06SEd Maste 	if (path == NULL || (credman && (cred_id != NULL || rp_id != NULL)))
2090afa8e06SEd Maste 		usage();
2100afa8e06SEd Maste 
2110afa8e06SEd Maste 	dev = open_dev(path);
2120afa8e06SEd Maste 
2130afa8e06SEd Maste 	if (credman)
2140afa8e06SEd Maste 		return (credman_get_metadata(dev, path));
2150afa8e06SEd Maste 	if (cred_id && rp_id)
2160afa8e06SEd Maste 		return (credman_print_rk(dev, path, rp_id, cred_id));
2170afa8e06SEd Maste 	if (cred_id || rp_id)
2180afa8e06SEd Maste 		usage();
2190afa8e06SEd Maste 
2200afa8e06SEd Maste 	print_attr(dev);
2210afa8e06SEd Maste 
2220afa8e06SEd Maste 	if (fido_dev_is_fido2(dev) == false)
2230afa8e06SEd Maste 		goto end;
2240afa8e06SEd Maste 	if ((ci = fido_cbor_info_new()) == NULL)
2250afa8e06SEd Maste 		errx(1, "fido_cbor_info_new");
2260afa8e06SEd Maste 	if ((r = fido_dev_get_cbor_info(dev, ci)) != FIDO_OK)
2270afa8e06SEd Maste 		errx(1, "fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r);
2280afa8e06SEd Maste 
2290afa8e06SEd Maste 	/* print supported protocol versions */
2300afa8e06SEd Maste 	print_str_array("version", fido_cbor_info_versions_ptr(ci),
2310afa8e06SEd Maste 	    fido_cbor_info_versions_len(ci));
2320afa8e06SEd Maste 
2330afa8e06SEd Maste 	/* print supported extensions */
2340afa8e06SEd Maste 	print_str_array("extension", fido_cbor_info_extensions_ptr(ci),
2350afa8e06SEd Maste 	    fido_cbor_info_extensions_len(ci));
2360afa8e06SEd Maste 
2370afa8e06SEd Maste 	/* print supported transports */
2380afa8e06SEd Maste 	print_str_array("transport", fido_cbor_info_transports_ptr(ci),
2390afa8e06SEd Maste 	    fido_cbor_info_transports_len(ci));
2400afa8e06SEd Maste 
2410afa8e06SEd Maste 	/* print supported algorithms */
2420afa8e06SEd Maste 	print_algorithms(ci);
2430afa8e06SEd Maste 
2440afa8e06SEd Maste 	/* print aaguid */
2450afa8e06SEd Maste 	print_aaguid(fido_cbor_info_aaguid_ptr(ci),
2460afa8e06SEd Maste 	    fido_cbor_info_aaguid_len(ci));
2470afa8e06SEd Maste 
2480afa8e06SEd Maste 	/* print supported options */
2490afa8e06SEd Maste 	print_opt_array("options", fido_cbor_info_options_name_ptr(ci),
2500afa8e06SEd Maste 	    fido_cbor_info_options_value_ptr(ci),
2510afa8e06SEd Maste 	    fido_cbor_info_options_len(ci));
2520afa8e06SEd Maste 
2530afa8e06SEd Maste 	/* print maximum message size */
2540afa8e06SEd Maste 	print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci));
2550afa8e06SEd Maste 
2560afa8e06SEd Maste 	/* print maximum number of credentials allowed in credential lists */
2570afa8e06SEd Maste 	print_maxcredcntlst(fido_cbor_info_maxcredcntlst(ci));
2580afa8e06SEd Maste 
2590afa8e06SEd Maste 	/* print maximum length of a credential ID */
2600afa8e06SEd Maste 	print_maxcredidlen(fido_cbor_info_maxcredidlen(ci));
2610afa8e06SEd Maste 
2620afa8e06SEd Maste 	/* print firmware version */
2630afa8e06SEd Maste 	print_fwversion(fido_cbor_info_fwversion(ci));
2640afa8e06SEd Maste 
2650afa8e06SEd Maste 	/* print supported pin protocols */
2660afa8e06SEd Maste 	print_byte_array("pin protocols", fido_cbor_info_protocols_ptr(ci),
2670afa8e06SEd Maste 	    fido_cbor_info_protocols_len(ci));
2680afa8e06SEd Maste 
2690afa8e06SEd Maste 	if (fido_dev_get_retry_count(dev, &retrycnt) != FIDO_OK)
2700afa8e06SEd Maste 		printf("pin retries: undefined\n");
2710afa8e06SEd Maste 	else
2720afa8e06SEd Maste 		printf("pin retries: %d\n", retrycnt);
2730afa8e06SEd Maste 
2740afa8e06SEd Maste 	if (fido_dev_get_uv_retry_count(dev, &retrycnt) != FIDO_OK)
2750afa8e06SEd Maste 		printf("uv retries: undefined\n");
2760afa8e06SEd Maste 	else
2770afa8e06SEd Maste 		printf("uv retries: %d\n", retrycnt);
2780afa8e06SEd Maste 
2790afa8e06SEd Maste 	bio_info(dev);
2800afa8e06SEd Maste 
2810afa8e06SEd Maste 	fido_cbor_info_free(&ci);
2820afa8e06SEd Maste end:
2830afa8e06SEd Maste 	fido_dev_close(dev);
2840afa8e06SEd Maste 	fido_dev_free(&dev);
2850afa8e06SEd Maste 
2860afa8e06SEd Maste 	exit(0);
2870afa8e06SEd Maste }
2880afa8e06SEd Maste 
2890afa8e06SEd Maste int
2900afa8e06SEd Maste token_reset(char *path)
2910afa8e06SEd Maste {
2920afa8e06SEd Maste 	fido_dev_t *dev = NULL;
2930afa8e06SEd Maste 	int r;
2940afa8e06SEd Maste 
2950afa8e06SEd Maste 	if (path == NULL)
2960afa8e06SEd Maste 		usage();
2970afa8e06SEd Maste 
2980afa8e06SEd Maste 	dev = open_dev(path);
2990afa8e06SEd Maste 	if ((r = fido_dev_reset(dev)) != FIDO_OK)
3000afa8e06SEd Maste 		errx(1, "fido_dev_reset: %s", fido_strerr(r));
3010afa8e06SEd Maste 
3020afa8e06SEd Maste 	fido_dev_close(dev);
3030afa8e06SEd Maste 	fido_dev_free(&dev);
3040afa8e06SEd Maste 
3050afa8e06SEd Maste 	exit(0);
3060afa8e06SEd Maste }
3070afa8e06SEd Maste 
3080afa8e06SEd Maste int
3090afa8e06SEd Maste token_get(int argc, char **argv, char *path)
3100afa8e06SEd Maste {
3110afa8e06SEd Maste 	char	*id = NULL;
3120afa8e06SEd Maste 	char	*key = NULL;
3130afa8e06SEd Maste 	char	*name = NULL;
3140afa8e06SEd Maste 	int	 blob = 0;
3150afa8e06SEd Maste 	int	 ch;
3160afa8e06SEd Maste 
3170afa8e06SEd Maste 	optind = 1;
3180afa8e06SEd Maste 
3190afa8e06SEd Maste 	while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
3200afa8e06SEd Maste 		switch (ch) {
3210afa8e06SEd Maste 		case 'b':
3220afa8e06SEd Maste 			blob = 1;
3230afa8e06SEd Maste 			break;
3240afa8e06SEd Maste 		case 'i':
3250afa8e06SEd Maste 			id = optarg;
3260afa8e06SEd Maste 			break;
3270afa8e06SEd Maste 		case 'k':
3280afa8e06SEd Maste 			key = optarg;
3290afa8e06SEd Maste 			break;
3300afa8e06SEd Maste 		case 'n':
3310afa8e06SEd Maste 			name = optarg;
3320afa8e06SEd Maste 			break;
3330afa8e06SEd Maste 		default:
3340afa8e06SEd Maste 			break; /* ignore */
3350afa8e06SEd Maste 		}
3360afa8e06SEd Maste 	}
3370afa8e06SEd Maste 
3380afa8e06SEd Maste 	argc -= optind;
3390afa8e06SEd Maste 	argv += optind;
3400afa8e06SEd Maste 
3410afa8e06SEd Maste 	if (blob == 0 || argc != 2)
3420afa8e06SEd Maste 		usage();
3430afa8e06SEd Maste 
3440afa8e06SEd Maste 	return blob_get(path, key, name, id, argv[0]);
3450afa8e06SEd Maste }
3460afa8e06SEd Maste 
3470afa8e06SEd Maste int
3480afa8e06SEd Maste token_set(int argc, char **argv, char *path)
3490afa8e06SEd Maste {
3500afa8e06SEd Maste 	char	*id = NULL;
3510afa8e06SEd Maste 	char	*key = NULL;
3520afa8e06SEd Maste 	char	*len = NULL;
3530afa8e06SEd Maste 	char	*display_name = NULL;
3540afa8e06SEd Maste 	char	*name = NULL;
355*f540a430SEd Maste 	char	*rpid = NULL;
3560afa8e06SEd Maste 	int	 blob = 0;
3570afa8e06SEd Maste 	int	 cred = 0;
3580afa8e06SEd Maste 	int	 ch;
3590afa8e06SEd Maste 	int	 enroll = 0;
3600afa8e06SEd Maste 	int	 ea = 0;
3610afa8e06SEd Maste 	int	 uv = 0;
3620afa8e06SEd Maste 	bool	 force = false;
3630afa8e06SEd Maste 
3640afa8e06SEd Maste 	optind = 1;
3650afa8e06SEd Maste 
3660afa8e06SEd Maste 	while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
3670afa8e06SEd Maste 		switch (ch) {
3680afa8e06SEd Maste 		case 'a':
3690afa8e06SEd Maste 			ea = 1;
3700afa8e06SEd Maste 			break;
3710afa8e06SEd Maste 		case 'b':
3720afa8e06SEd Maste 			blob = 1;
3730afa8e06SEd Maste 			break;
3740afa8e06SEd Maste 		case 'c':
3750afa8e06SEd Maste 			cred = 1;
3760afa8e06SEd Maste 			break;
3770afa8e06SEd Maste 		case 'e':
3780afa8e06SEd Maste 			enroll = 1;
3790afa8e06SEd Maste 			break;
3800afa8e06SEd Maste 		case 'f':
3810afa8e06SEd Maste 			force = true;
3820afa8e06SEd Maste 			break;
3830afa8e06SEd Maste 		case 'i':
3840afa8e06SEd Maste 			id = optarg;
3850afa8e06SEd Maste 			break;
3860afa8e06SEd Maste 		case 'k':
3870afa8e06SEd Maste 			key = optarg;
3880afa8e06SEd Maste 			break;
3890afa8e06SEd Maste 		case 'l':
3900afa8e06SEd Maste 			len = optarg;
3910afa8e06SEd Maste 			break;
3920afa8e06SEd Maste 		case 'p':
3930afa8e06SEd Maste 			display_name = optarg;
3940afa8e06SEd Maste 			break;
395*f540a430SEd Maste 		case 'm':
396*f540a430SEd Maste 			rpid = optarg;
397*f540a430SEd Maste 			break;
3980afa8e06SEd Maste 		case 'n':
3990afa8e06SEd Maste 			name = optarg;
4000afa8e06SEd Maste 			break;
4010afa8e06SEd Maste 		case 'u':
4020afa8e06SEd Maste 			uv = 1;
4030afa8e06SEd Maste 			break;
4040afa8e06SEd Maste 		default:
4050afa8e06SEd Maste 			break; /* ignore */
4060afa8e06SEd Maste 		}
4070afa8e06SEd Maste 	}
4080afa8e06SEd Maste 
4090afa8e06SEd Maste 	argc -= optind;
4100afa8e06SEd Maste 	argv += optind;
4110afa8e06SEd Maste 
4120afa8e06SEd Maste 	if (path == NULL)
4130afa8e06SEd Maste 		usage();
4140afa8e06SEd Maste 
4150afa8e06SEd Maste 	if (blob) {
4160afa8e06SEd Maste 		if (argc != 2)
4170afa8e06SEd Maste 			usage();
4180afa8e06SEd Maste 		return (blob_set(path, key, name, id, argv[0]));
4190afa8e06SEd Maste 	}
4200afa8e06SEd Maste 
4210afa8e06SEd Maste 	if (cred) {
4220afa8e06SEd Maste 		if (!id || !key)
4230afa8e06SEd Maste 			usage();
4240afa8e06SEd Maste 		if (!name && !display_name)
4250afa8e06SEd Maste 			usage();
4260afa8e06SEd Maste 		return (credman_update_rk(path, key, id, name, display_name));
4270afa8e06SEd Maste 	}
4280afa8e06SEd Maste 
4290afa8e06SEd Maste 	if (enroll) {
4300afa8e06SEd Maste 		if (ea || uv)
4310afa8e06SEd Maste 			usage();
4320afa8e06SEd Maste 		if (id && name)
4330afa8e06SEd Maste 			return (bio_set_name(path, id, name));
4340afa8e06SEd Maste 		if (!id && !name)
4350afa8e06SEd Maste 			return (bio_enroll(path));
4360afa8e06SEd Maste 		usage();
4370afa8e06SEd Maste 	}
4380afa8e06SEd Maste 
4390afa8e06SEd Maste 	if (ea) {
4400afa8e06SEd Maste 		if (uv)
4410afa8e06SEd Maste 			usage();
4420afa8e06SEd Maste 		return (config_entattest(path));
4430afa8e06SEd Maste 	}
4440afa8e06SEd Maste 
4450afa8e06SEd Maste 	if (len)
4460afa8e06SEd Maste 		return (config_pin_minlen(path, len));
447*f540a430SEd Maste 	if (rpid)
448*f540a430SEd Maste 		return (config_pin_minlen_rpid(path, rpid));
4490afa8e06SEd Maste 	if (force)
4500afa8e06SEd Maste 		return (config_force_pin_change(path));
4510afa8e06SEd Maste 	if (uv)
4520afa8e06SEd Maste 		return (config_always_uv(path, 1));
4530afa8e06SEd Maste 
4540afa8e06SEd Maste 	return (pin_set(path));
4550afa8e06SEd Maste }
4560afa8e06SEd Maste 
4570afa8e06SEd Maste int
4580afa8e06SEd Maste token_list(int argc, char **argv, char *path)
4590afa8e06SEd Maste {
4600afa8e06SEd Maste 	fido_dev_info_t *devlist;
4610afa8e06SEd Maste 	size_t ndevs;
4620afa8e06SEd Maste 	const char *rp_id = NULL;
4630afa8e06SEd Maste 	int blobs = 0;
4640afa8e06SEd Maste 	int enrolls = 0;
4650afa8e06SEd Maste 	int keys = 0;
4660afa8e06SEd Maste 	int rplist = 0;
4670afa8e06SEd Maste 	int ch;
4680afa8e06SEd Maste 	int r;
4690afa8e06SEd Maste 
4700afa8e06SEd Maste 	optind = 1;
4710afa8e06SEd Maste 
4720afa8e06SEd Maste 	while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
4730afa8e06SEd Maste 		switch (ch) {
4740afa8e06SEd Maste 		case 'b':
4750afa8e06SEd Maste 			blobs = 1;
4760afa8e06SEd Maste 			break;
4770afa8e06SEd Maste 		case 'e':
4780afa8e06SEd Maste 			enrolls = 1;
4790afa8e06SEd Maste 			break;
4800afa8e06SEd Maste 		case 'k':
4810afa8e06SEd Maste 			keys = 1;
4820afa8e06SEd Maste 			rp_id = optarg;
4830afa8e06SEd Maste 			break;
4840afa8e06SEd Maste 		case 'r':
4850afa8e06SEd Maste 			rplist = 1;
4860afa8e06SEd Maste 			break;
4870afa8e06SEd Maste 		default:
4880afa8e06SEd Maste 			break; /* ignore */
4890afa8e06SEd Maste 		}
4900afa8e06SEd Maste 	}
4910afa8e06SEd Maste 
4920afa8e06SEd Maste 	if (blobs || enrolls || keys || rplist) {
4930afa8e06SEd Maste 		if (path == NULL)
4940afa8e06SEd Maste 			usage();
4950afa8e06SEd Maste 		if (blobs)
4960afa8e06SEd Maste 			return (blob_list(path));
4970afa8e06SEd Maste 		if (enrolls)
4980afa8e06SEd Maste 			return (bio_list(path));
4990afa8e06SEd Maste 		if (keys)
5000afa8e06SEd Maste 			return (credman_list_rk(path, rp_id));
5010afa8e06SEd Maste 		if (rplist)
5020afa8e06SEd Maste 			return (credman_list_rp(path));
5030afa8e06SEd Maste 		/* NOTREACHED */
5040afa8e06SEd Maste 	}
5050afa8e06SEd Maste 
5060afa8e06SEd Maste 	if ((devlist = fido_dev_info_new(64)) == NULL)
5070afa8e06SEd Maste 		errx(1, "fido_dev_info_new");
5080afa8e06SEd Maste 	if ((r = fido_dev_info_manifest(devlist, 64, &ndevs)) != FIDO_OK)
5090afa8e06SEd Maste 		errx(1, "fido_dev_info_manifest: %s (0x%x)", fido_strerr(r), r);
5100afa8e06SEd Maste 
5110afa8e06SEd Maste 	for (size_t i = 0; i < ndevs; i++) {
5120afa8e06SEd Maste 		const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i);
5130afa8e06SEd Maste 		printf("%s: vendor=0x%04x, product=0x%04x (%s %s)\n",
5140afa8e06SEd Maste 		    fido_dev_info_path(di),
5150afa8e06SEd Maste 		    (uint16_t)fido_dev_info_vendor(di),
5160afa8e06SEd Maste 		    (uint16_t)fido_dev_info_product(di),
5170afa8e06SEd Maste 		    fido_dev_info_manufacturer_string(di),
5180afa8e06SEd Maste 		    fido_dev_info_product_string(di));
5190afa8e06SEd Maste 	}
5200afa8e06SEd Maste 
5210afa8e06SEd Maste 	fido_dev_info_free(&devlist, ndevs);
5220afa8e06SEd Maste 
5230afa8e06SEd Maste 	exit(0);
5240afa8e06SEd Maste }
5250afa8e06SEd Maste 
5260afa8e06SEd Maste int
5270afa8e06SEd Maste token_delete(int argc, char **argv, char *path)
5280afa8e06SEd Maste {
5290afa8e06SEd Maste 	char		*id = NULL;
5300afa8e06SEd Maste 	char		*key = NULL;
5310afa8e06SEd Maste 	char		*name = NULL;
5320afa8e06SEd Maste 	int		 blob = 0;
5330afa8e06SEd Maste 	int		 ch;
5340afa8e06SEd Maste 	int		 enroll = 0;
5350afa8e06SEd Maste 	int		 uv = 0;
5360afa8e06SEd Maste 
5370afa8e06SEd Maste 	optind = 1;
5380afa8e06SEd Maste 
5390afa8e06SEd Maste 	while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
5400afa8e06SEd Maste 		switch (ch) {
5410afa8e06SEd Maste 		case 'b':
5420afa8e06SEd Maste 			blob = 1;
5430afa8e06SEd Maste 			break;
5440afa8e06SEd Maste 		case 'e':
5450afa8e06SEd Maste 			enroll = 1;
5460afa8e06SEd Maste 			break;
5470afa8e06SEd Maste 		case 'i':
5480afa8e06SEd Maste 			id = optarg;
5490afa8e06SEd Maste 			break;
5500afa8e06SEd Maste 		case 'k':
5510afa8e06SEd Maste 			key = optarg;
5520afa8e06SEd Maste 			break;
5530afa8e06SEd Maste 		case 'n':
5540afa8e06SEd Maste 			name = optarg;
5550afa8e06SEd Maste 			break;
5560afa8e06SEd Maste 		case 'u':
5570afa8e06SEd Maste 			uv = 1;
5580afa8e06SEd Maste 			break;
5590afa8e06SEd Maste 		default:
5600afa8e06SEd Maste 			break; /* ignore */
5610afa8e06SEd Maste 		}
5620afa8e06SEd Maste 	}
5630afa8e06SEd Maste 
5640afa8e06SEd Maste 	if (path == NULL)
5650afa8e06SEd Maste 		usage();
5660afa8e06SEd Maste 
5670afa8e06SEd Maste 	if (blob)
5680afa8e06SEd Maste 		return (blob_delete(path, key, name, id));
5690afa8e06SEd Maste 
5700afa8e06SEd Maste 	if (id) {
5710afa8e06SEd Maste 		if (uv)
5720afa8e06SEd Maste 			usage();
5730afa8e06SEd Maste 		if (enroll == 0)
5740afa8e06SEd Maste 			return (credman_delete_rk(path, id));
5750afa8e06SEd Maste 		return (bio_delete(path, id));
5760afa8e06SEd Maste 	}
5770afa8e06SEd Maste 
5780afa8e06SEd Maste 	if (uv == 0)
5790afa8e06SEd Maste 		usage();
5800afa8e06SEd Maste 
5810afa8e06SEd Maste 	return (config_always_uv(path, 0));
5820afa8e06SEd Maste }
583