xref: /freebsd/contrib/libfido2/examples/info.c (revision 2ccfa855b2fc331819953e3de1b1c15ce5b95a7e)
10afa8e06SEd Maste /*
2*2ccfa855SEd Maste  * Copyright (c) 2018-2022 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.
5*2ccfa855SEd Maste  * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste  */
70afa8e06SEd Maste 
80afa8e06SEd Maste #include <fido.h>
90afa8e06SEd Maste #include <stdbool.h>
100afa8e06SEd Maste #include <stdint.h>
110afa8e06SEd Maste #include <stdio.h>
120afa8e06SEd Maste #include <stdlib.h>
130afa8e06SEd Maste #include <string.h>
140afa8e06SEd Maste 
150afa8e06SEd Maste #include "../openbsd-compat/openbsd-compat.h"
160afa8e06SEd Maste 
170afa8e06SEd Maste /*
180afa8e06SEd Maste  * Pretty-print a device's capabilities flags and return the result.
190afa8e06SEd Maste  */
200afa8e06SEd Maste static void
format_flags(char * ret,size_t retlen,uint8_t flags)210afa8e06SEd Maste format_flags(char *ret, size_t retlen, uint8_t flags)
220afa8e06SEd Maste {
230afa8e06SEd Maste 	memset(ret, 0, retlen);
240afa8e06SEd Maste 
250afa8e06SEd Maste 	if (flags & FIDO_CAP_WINK) {
260afa8e06SEd Maste 		if (strlcat(ret, "wink,", retlen) >= retlen)
270afa8e06SEd Maste 			goto toolong;
280afa8e06SEd Maste 	} else {
290afa8e06SEd Maste 		if (strlcat(ret, "nowink,", retlen) >= retlen)
300afa8e06SEd Maste 			goto toolong;
310afa8e06SEd Maste 	}
320afa8e06SEd Maste 
330afa8e06SEd Maste 	if (flags & FIDO_CAP_CBOR) {
340afa8e06SEd Maste 		if (strlcat(ret, " cbor,", retlen) >= retlen)
350afa8e06SEd Maste 			goto toolong;
360afa8e06SEd Maste 	} else {
370afa8e06SEd Maste 		if (strlcat(ret, " nocbor,", retlen) >= retlen)
380afa8e06SEd Maste 			goto toolong;
390afa8e06SEd Maste 	}
400afa8e06SEd Maste 
410afa8e06SEd Maste 	if (flags & FIDO_CAP_NMSG) {
420afa8e06SEd Maste 		if (strlcat(ret, " nomsg", retlen) >= retlen)
430afa8e06SEd Maste 			goto toolong;
440afa8e06SEd Maste 	} else {
450afa8e06SEd Maste 		if (strlcat(ret, " msg", retlen) >= retlen)
460afa8e06SEd Maste 			goto toolong;
470afa8e06SEd Maste 	}
480afa8e06SEd Maste 
490afa8e06SEd Maste 	return;
500afa8e06SEd Maste toolong:
510afa8e06SEd Maste 	strlcpy(ret, "toolong", retlen);
520afa8e06SEd Maste }
530afa8e06SEd Maste 
540afa8e06SEd Maste /*
550afa8e06SEd Maste  * Print a FIDO device's attributes on stdout.
560afa8e06SEd Maste  */
570afa8e06SEd Maste static void
print_attr(const fido_dev_t * dev)580afa8e06SEd Maste print_attr(const fido_dev_t *dev)
590afa8e06SEd Maste {
600afa8e06SEd Maste 	char flags_txt[128];
610afa8e06SEd Maste 
620afa8e06SEd Maste 	printf("proto: 0x%02x\n", fido_dev_protocol(dev));
630afa8e06SEd Maste 	printf("major: 0x%02x\n", fido_dev_major(dev));
640afa8e06SEd Maste 	printf("minor: 0x%02x\n", fido_dev_minor(dev));
650afa8e06SEd Maste 	printf("build: 0x%02x\n", fido_dev_build(dev));
660afa8e06SEd Maste 
670afa8e06SEd Maste 	format_flags(flags_txt, sizeof(flags_txt), fido_dev_flags(dev));
680afa8e06SEd Maste 	printf("caps: 0x%02x (%s)\n", fido_dev_flags(dev), flags_txt);
690afa8e06SEd Maste }
700afa8e06SEd Maste 
710afa8e06SEd Maste /*
720afa8e06SEd Maste  * Auxiliary function to print an array of strings on stdout.
730afa8e06SEd Maste  */
740afa8e06SEd Maste static void
print_str_array(const char * label,char * const * sa,size_t len)750afa8e06SEd Maste print_str_array(const char *label, char * const *sa, size_t len)
760afa8e06SEd Maste {
770afa8e06SEd Maste 	if (len == 0)
780afa8e06SEd Maste 		return;
790afa8e06SEd Maste 
800afa8e06SEd Maste 	printf("%s strings: ", label);
810afa8e06SEd Maste 
820afa8e06SEd Maste 	for (size_t i = 0; i < len; i++)
830afa8e06SEd Maste 		printf("%s%s", i > 0 ? ", " : "", sa[i]);
840afa8e06SEd Maste 
850afa8e06SEd Maste 	printf("\n");
860afa8e06SEd Maste }
870afa8e06SEd Maste 
880afa8e06SEd Maste /*
890afa8e06SEd Maste  * Auxiliary function to print (char *, bool) pairs on stdout.
900afa8e06SEd Maste  */
910afa8e06SEd Maste static void
print_opt_array(const char * label,char * const * name,const bool * value,size_t len)920afa8e06SEd Maste print_opt_array(const char *label, char * const *name, const bool *value,
930afa8e06SEd Maste     size_t len)
940afa8e06SEd Maste {
950afa8e06SEd Maste 	if (len == 0)
960afa8e06SEd Maste 		return;
970afa8e06SEd Maste 
980afa8e06SEd Maste 	printf("%s: ", label);
990afa8e06SEd Maste 
1000afa8e06SEd Maste 	for (size_t i = 0; i < len; i++)
1010afa8e06SEd Maste 		printf("%s%s%s", i > 0 ? ", " : "",
1020afa8e06SEd Maste 		    value[i] ? "" : "no", name[i]);
1030afa8e06SEd Maste 
1040afa8e06SEd Maste 	printf("\n");
1050afa8e06SEd Maste }
1060afa8e06SEd Maste 
1070afa8e06SEd Maste /*
108*2ccfa855SEd Maste  * Auxiliary function to print (char *, uint64_t) pairs on stdout.
109*2ccfa855SEd Maste  */
110*2ccfa855SEd Maste static void
print_cert_array(const char * label,char * const * name,const uint64_t * value,size_t len)111*2ccfa855SEd Maste print_cert_array(const char *label, char * const *name, const uint64_t *value,
112*2ccfa855SEd Maste     size_t len)
113*2ccfa855SEd Maste {
114*2ccfa855SEd Maste 	if (len == 0)
115*2ccfa855SEd Maste 		return;
116*2ccfa855SEd Maste 
117*2ccfa855SEd Maste 	printf("%s: ", label);
118*2ccfa855SEd Maste 
119*2ccfa855SEd Maste 	for (size_t i = 0; i < len; i++)
120*2ccfa855SEd Maste 		printf("%s%s %llu", i > 0 ? ", " : "", name[i],
121*2ccfa855SEd Maste 		    (unsigned long long)value[i]);
122*2ccfa855SEd Maste 
123*2ccfa855SEd Maste 	printf("\n");
124*2ccfa855SEd Maste }
125*2ccfa855SEd Maste 
126*2ccfa855SEd Maste /*
1270afa8e06SEd Maste  * Auxiliary function to print a list of supported COSE algorithms on stdout.
1280afa8e06SEd Maste  */
1290afa8e06SEd Maste static void
print_algorithms(const fido_cbor_info_t * ci)1300afa8e06SEd Maste print_algorithms(const fido_cbor_info_t *ci)
1310afa8e06SEd Maste {
1320afa8e06SEd Maste 	const char *cose, *type;
1330afa8e06SEd Maste 	size_t len;
1340afa8e06SEd Maste 
1350afa8e06SEd Maste 	if ((len = fido_cbor_info_algorithm_count(ci)) == 0)
1360afa8e06SEd Maste 		return;
1370afa8e06SEd Maste 
1380afa8e06SEd Maste 	printf("algorithms: ");
1390afa8e06SEd Maste 
1400afa8e06SEd Maste 	for (size_t i = 0; i < len; i++) {
1410afa8e06SEd Maste 		cose = type = "unknown";
1420afa8e06SEd Maste 		switch (fido_cbor_info_algorithm_cose(ci, i)) {
1430afa8e06SEd Maste 		case COSE_ES256:
1440afa8e06SEd Maste 			cose = "es256";
1450afa8e06SEd Maste 			break;
146*2ccfa855SEd Maste 		case COSE_ES384:
147*2ccfa855SEd Maste 			cose = "es384";
148*2ccfa855SEd Maste 			break;
1490afa8e06SEd Maste 		case COSE_RS256:
1500afa8e06SEd Maste 			cose = "rs256";
1510afa8e06SEd Maste 			break;
152*2ccfa855SEd Maste 		case COSE_EDDSA:
153*2ccfa855SEd Maste 			cose = "eddsa";
154*2ccfa855SEd Maste 			break;
1550afa8e06SEd Maste 		}
1560afa8e06SEd Maste 		if (fido_cbor_info_algorithm_type(ci, i) != NULL)
1570afa8e06SEd Maste 			type = fido_cbor_info_algorithm_type(ci, i);
1580afa8e06SEd Maste 		printf("%s%s (%s)", i > 0 ? ", " : "", cose, type);
1590afa8e06SEd Maste 	}
1600afa8e06SEd Maste 
1610afa8e06SEd Maste 	printf("\n");
1620afa8e06SEd Maste }
1630afa8e06SEd Maste 
1640afa8e06SEd Maste /*
1650afa8e06SEd Maste  * Auxiliary function to print an authenticator's AAGUID on stdout.
1660afa8e06SEd Maste  */
1670afa8e06SEd Maste static void
print_aaguid(const unsigned char * buf,size_t buflen)1680afa8e06SEd Maste print_aaguid(const unsigned char *buf, size_t buflen)
1690afa8e06SEd Maste {
1700afa8e06SEd Maste 	printf("aaguid: ");
1710afa8e06SEd Maste 
1720afa8e06SEd Maste 	while (buflen--)
1730afa8e06SEd Maste 		printf("%02x", *buf++);
1740afa8e06SEd Maste 
1750afa8e06SEd Maste 	printf("\n");
1760afa8e06SEd Maste }
1770afa8e06SEd Maste 
1780afa8e06SEd Maste /*
1790afa8e06SEd Maste  * Auxiliary function to print an authenticator's maximum message size on
1800afa8e06SEd Maste  * stdout.
1810afa8e06SEd Maste  */
1820afa8e06SEd Maste static void
print_maxmsgsiz(uint64_t maxmsgsiz)1830afa8e06SEd Maste print_maxmsgsiz(uint64_t maxmsgsiz)
1840afa8e06SEd Maste {
1850afa8e06SEd Maste 	printf("maxmsgsiz: %d\n", (int)maxmsgsiz);
1860afa8e06SEd Maste }
1870afa8e06SEd Maste 
1880afa8e06SEd Maste /*
1890afa8e06SEd Maste  * Auxiliary function to print an authenticator's maximum number of credentials
1900afa8e06SEd Maste  * in a credential list on stdout.
1910afa8e06SEd Maste  */
1920afa8e06SEd Maste static void
print_maxcredcntlst(uint64_t maxcredcntlst)1930afa8e06SEd Maste print_maxcredcntlst(uint64_t maxcredcntlst)
1940afa8e06SEd Maste {
1950afa8e06SEd Maste 	printf("maxcredcntlst: %d\n", (int)maxcredcntlst);
1960afa8e06SEd Maste }
1970afa8e06SEd Maste 
1980afa8e06SEd Maste /*
1990afa8e06SEd Maste  * Auxiliary function to print an authenticator's maximum credential ID length
2000afa8e06SEd Maste  * on stdout.
2010afa8e06SEd Maste  */
2020afa8e06SEd Maste static void
print_maxcredidlen(uint64_t maxcredidlen)2030afa8e06SEd Maste print_maxcredidlen(uint64_t maxcredidlen)
2040afa8e06SEd Maste {
2050afa8e06SEd Maste 	printf("maxcredlen: %d\n", (int)maxcredidlen);
2060afa8e06SEd Maste }
2070afa8e06SEd Maste 
2080afa8e06SEd Maste /*
209*2ccfa855SEd Maste  * Auxiliary function to print the maximum size of an authenticator's
210*2ccfa855SEd Maste  * serialized largeBlob array.
211*2ccfa855SEd Maste  */
212*2ccfa855SEd Maste static void
print_maxlargeblob(uint64_t maxlargeblob)213*2ccfa855SEd Maste print_maxlargeblob(uint64_t maxlargeblob)
214*2ccfa855SEd Maste {
215*2ccfa855SEd Maste 	printf("maxlargeblob: %d\n", (int)maxlargeblob);
216*2ccfa855SEd Maste }
217*2ccfa855SEd Maste 
218*2ccfa855SEd Maste /*
219*2ccfa855SEd Maste  * Auxiliary function to print the authenticator's estimated number of
220*2ccfa855SEd Maste  * remaining resident credentials.
221*2ccfa855SEd Maste  */
222*2ccfa855SEd Maste static void
print_rk_remaining(int64_t rk_remaining)223*2ccfa855SEd Maste print_rk_remaining(int64_t rk_remaining)
224*2ccfa855SEd Maste {
225*2ccfa855SEd Maste 	printf("remaining rk(s): ");
226*2ccfa855SEd Maste 
227*2ccfa855SEd Maste 	if (rk_remaining == -1)
228*2ccfa855SEd Maste 		printf("undefined\n");
229*2ccfa855SEd Maste 	else
230*2ccfa855SEd Maste 		printf("%d\n", (int)rk_remaining);
231*2ccfa855SEd Maste }
232*2ccfa855SEd Maste 
233*2ccfa855SEd Maste /*
234*2ccfa855SEd Maste  * Auxiliary function to print the minimum pin length observed by the
235*2ccfa855SEd Maste  * authenticator.
236*2ccfa855SEd Maste  */
237*2ccfa855SEd Maste static void
print_minpinlen(uint64_t minpinlen)238*2ccfa855SEd Maste print_minpinlen(uint64_t minpinlen)
239*2ccfa855SEd Maste {
240*2ccfa855SEd Maste 	printf("minpinlen: %d\n", (int)minpinlen);
241*2ccfa855SEd Maste }
242*2ccfa855SEd Maste 
243*2ccfa855SEd Maste /*
244*2ccfa855SEd Maste  * Auxiliary function to print the authenticator's preferred (platform)
245*2ccfa855SEd Maste  * UV attempts.
246*2ccfa855SEd Maste  */
247*2ccfa855SEd Maste static void
print_uv_attempts(uint64_t uv_attempts)248*2ccfa855SEd Maste print_uv_attempts(uint64_t uv_attempts)
249*2ccfa855SEd Maste {
250*2ccfa855SEd Maste 	printf("platform uv attempt(s): %d\n", (int)uv_attempts);
251*2ccfa855SEd Maste }
252*2ccfa855SEd Maste 
253*2ccfa855SEd Maste /*
2540afa8e06SEd Maste  * Auxiliary function to print an authenticator's firmware version on stdout.
2550afa8e06SEd Maste  */
2560afa8e06SEd Maste static void
print_fwversion(uint64_t fwversion)2570afa8e06SEd Maste print_fwversion(uint64_t fwversion)
2580afa8e06SEd Maste {
2590afa8e06SEd Maste 	printf("fwversion: 0x%x\n", (int)fwversion);
2600afa8e06SEd Maste }
2610afa8e06SEd Maste 
2620afa8e06SEd Maste /*
2630afa8e06SEd Maste  * Auxiliary function to print an array of bytes on stdout.
2640afa8e06SEd Maste  */
2650afa8e06SEd Maste static void
print_byte_array(const char * label,const uint8_t * ba,size_t len)2660afa8e06SEd Maste print_byte_array(const char *label, const uint8_t *ba, size_t len)
2670afa8e06SEd Maste {
2680afa8e06SEd Maste 	if (len == 0)
2690afa8e06SEd Maste 		return;
2700afa8e06SEd Maste 
2710afa8e06SEd Maste 	printf("%s: ", label);
2720afa8e06SEd Maste 
2730afa8e06SEd Maste 	for (size_t i = 0; i < len; i++)
2740afa8e06SEd Maste 		printf("%s%u", i > 0 ? ", " : "", (unsigned)ba[i]);
2750afa8e06SEd Maste 
2760afa8e06SEd Maste 	printf("\n");
2770afa8e06SEd Maste }
2780afa8e06SEd Maste 
2790afa8e06SEd Maste static void
getinfo(const char * path)2800afa8e06SEd Maste getinfo(const char *path)
2810afa8e06SEd Maste {
2820afa8e06SEd Maste 	fido_dev_t		*dev;
2830afa8e06SEd Maste 	fido_cbor_info_t	*ci;
2840afa8e06SEd Maste 	int			 r;
2850afa8e06SEd Maste 
2860afa8e06SEd Maste 	fido_init(0);
2870afa8e06SEd Maste 
2880afa8e06SEd Maste 	if ((dev = fido_dev_new()) == NULL)
2890afa8e06SEd Maste 		errx(1, "fido_dev_new");
2900afa8e06SEd Maste 	if ((r = fido_dev_open(dev, path)) != FIDO_OK)
2910afa8e06SEd Maste 		errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r);
2920afa8e06SEd Maste 
2930afa8e06SEd Maste 	print_attr(dev);
2940afa8e06SEd Maste 
2950afa8e06SEd Maste 	if (fido_dev_is_fido2(dev) == false)
2960afa8e06SEd Maste 		goto end;
2970afa8e06SEd Maste 	if ((ci = fido_cbor_info_new()) == NULL)
2980afa8e06SEd Maste 		errx(1, "fido_cbor_info_new");
2990afa8e06SEd Maste 	if ((r = fido_dev_get_cbor_info(dev, ci)) != FIDO_OK)
3000afa8e06SEd Maste 		errx(1, "fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r);
3010afa8e06SEd Maste 
3020afa8e06SEd Maste 	/* print supported protocol versions */
3030afa8e06SEd Maste 	print_str_array("version", fido_cbor_info_versions_ptr(ci),
3040afa8e06SEd Maste 	    fido_cbor_info_versions_len(ci));
3050afa8e06SEd Maste 
3060afa8e06SEd Maste 	/* print supported extensions */
3070afa8e06SEd Maste 	print_str_array("extension", fido_cbor_info_extensions_ptr(ci),
3080afa8e06SEd Maste 	    fido_cbor_info_extensions_len(ci));
3090afa8e06SEd Maste 
3100afa8e06SEd Maste 	/* print supported transports */
3110afa8e06SEd Maste 	print_str_array("transport", fido_cbor_info_transports_ptr(ci),
3120afa8e06SEd Maste 	    fido_cbor_info_transports_len(ci));
3130afa8e06SEd Maste 
3140afa8e06SEd Maste 	/* print supported algorithms */
3150afa8e06SEd Maste 	print_algorithms(ci);
3160afa8e06SEd Maste 
3170afa8e06SEd Maste 	/* print aaguid */
3180afa8e06SEd Maste 	print_aaguid(fido_cbor_info_aaguid_ptr(ci),
3190afa8e06SEd Maste 	    fido_cbor_info_aaguid_len(ci));
3200afa8e06SEd Maste 
3210afa8e06SEd Maste 	/* print supported options */
3220afa8e06SEd Maste 	print_opt_array("options", fido_cbor_info_options_name_ptr(ci),
3230afa8e06SEd Maste 	    fido_cbor_info_options_value_ptr(ci),
3240afa8e06SEd Maste 	    fido_cbor_info_options_len(ci));
3250afa8e06SEd Maste 
326*2ccfa855SEd Maste 	/* print certifications */
327*2ccfa855SEd Maste 	print_cert_array("certifications", fido_cbor_info_certs_name_ptr(ci),
328*2ccfa855SEd Maste 	    fido_cbor_info_certs_value_ptr(ci),
329*2ccfa855SEd Maste 	    fido_cbor_info_certs_len(ci));
330*2ccfa855SEd Maste 
331*2ccfa855SEd Maste 	/* print firmware version */
332*2ccfa855SEd Maste 	print_fwversion(fido_cbor_info_fwversion(ci));
333*2ccfa855SEd Maste 
3340afa8e06SEd Maste 	/* print maximum message size */
3350afa8e06SEd Maste 	print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci));
3360afa8e06SEd Maste 
3370afa8e06SEd Maste 	/* print maximum number of credentials allowed in credential lists */
3380afa8e06SEd Maste 	print_maxcredcntlst(fido_cbor_info_maxcredcntlst(ci));
3390afa8e06SEd Maste 
3400afa8e06SEd Maste 	/* print maximum length of a credential ID */
3410afa8e06SEd Maste 	print_maxcredidlen(fido_cbor_info_maxcredidlen(ci));
3420afa8e06SEd Maste 
343*2ccfa855SEd Maste 	/* print maximum length of largeBlob array */
344*2ccfa855SEd Maste 	print_maxlargeblob(fido_cbor_info_maxlargeblob(ci));
345*2ccfa855SEd Maste 
346*2ccfa855SEd Maste 	/* print number of remaining resident credentials */
347*2ccfa855SEd Maste 	print_rk_remaining(fido_cbor_info_rk_remaining(ci));
348*2ccfa855SEd Maste 
349*2ccfa855SEd Maste 	/* print minimum pin length */
350*2ccfa855SEd Maste 	print_minpinlen(fido_cbor_info_minpinlen(ci));
3510afa8e06SEd Maste 
3520afa8e06SEd Maste 	/* print supported pin protocols */
3530afa8e06SEd Maste 	print_byte_array("pin protocols", fido_cbor_info_protocols_ptr(ci),
3540afa8e06SEd Maste 	    fido_cbor_info_protocols_len(ci));
3550afa8e06SEd Maste 
356*2ccfa855SEd Maste 	/* print whether a new pin is required */
357*2ccfa855SEd Maste 	printf("pin change required: %s\n",
358*2ccfa855SEd Maste 	    fido_cbor_info_new_pin_required(ci) ? "true" : "false");
359*2ccfa855SEd Maste 
360*2ccfa855SEd Maste 	/* print platform uv attempts */
361*2ccfa855SEd Maste 	print_uv_attempts(fido_cbor_info_uv_attempts(ci));
362*2ccfa855SEd Maste 
3630afa8e06SEd Maste 	fido_cbor_info_free(&ci);
3640afa8e06SEd Maste end:
3650afa8e06SEd Maste 	if ((r = fido_dev_close(dev)) != FIDO_OK)
3660afa8e06SEd Maste 		errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r);
3670afa8e06SEd Maste 
3680afa8e06SEd Maste 	fido_dev_free(&dev);
3690afa8e06SEd Maste }
3700afa8e06SEd Maste 
3710afa8e06SEd Maste int
main(int argc,char ** argv)3720afa8e06SEd Maste main(int argc, char **argv)
3730afa8e06SEd Maste {
3740afa8e06SEd Maste 	if (argc != 2) {
3750afa8e06SEd Maste 		fprintf(stderr, "usage: info <device>\n");
3760afa8e06SEd Maste 		exit(EXIT_FAILURE);
3770afa8e06SEd Maste 	}
3780afa8e06SEd Maste 
3790afa8e06SEd Maste 	getinfo(argv[1]);
3800afa8e06SEd Maste 
3810afa8e06SEd Maste 	exit(0);
3820afa8e06SEd Maste }
383