xref: /netbsd-src/external/bsd/libfido2/dist/examples/info.c (revision 2d40c4512a84c0d064ec30a492c5e2a14d230bc3)
1ba9bdd8bSchristos /*
2*2d40c451Schristos  * Copyright (c) 2018-2022 Yubico AB. All rights reserved.
3ba9bdd8bSchristos  * Use of this source code is governed by a BSD-style
4ba9bdd8bSchristos  * license that can be found in the LICENSE file.
5*2d40c451Schristos  * SPDX-License-Identifier: BSD-2-Clause
6ba9bdd8bSchristos  */
7ba9bdd8bSchristos 
895dbdf32Schristos #include <fido.h>
9ba9bdd8bSchristos #include <stdbool.h>
10ba9bdd8bSchristos #include <stdint.h>
11ba9bdd8bSchristos #include <stdio.h>
12ba9bdd8bSchristos #include <stdlib.h>
13ba9bdd8bSchristos #include <string.h>
14ba9bdd8bSchristos 
151fc1e710Schristos #include "../openbsd-compat/openbsd-compat.h"
16ba9bdd8bSchristos 
17ba9bdd8bSchristos /*
18ba9bdd8bSchristos  * Pretty-print a device's capabilities flags and return the result.
19ba9bdd8bSchristos  */
20ba9bdd8bSchristos static void
format_flags(char * ret,size_t retlen,uint8_t flags)21ba9bdd8bSchristos format_flags(char *ret, size_t retlen, uint8_t flags)
22ba9bdd8bSchristos {
23ba9bdd8bSchristos 	memset(ret, 0, retlen);
24ba9bdd8bSchristos 
25ba9bdd8bSchristos 	if (flags & FIDO_CAP_WINK) {
26ba9bdd8bSchristos 		if (strlcat(ret, "wink,", retlen) >= retlen)
27ba9bdd8bSchristos 			goto toolong;
28ba9bdd8bSchristos 	} else {
29ba9bdd8bSchristos 		if (strlcat(ret, "nowink,", retlen) >= retlen)
30ba9bdd8bSchristos 			goto toolong;
31ba9bdd8bSchristos 	}
32ba9bdd8bSchristos 
33ba9bdd8bSchristos 	if (flags & FIDO_CAP_CBOR) {
34ba9bdd8bSchristos 		if (strlcat(ret, " cbor,", retlen) >= retlen)
35ba9bdd8bSchristos 			goto toolong;
36ba9bdd8bSchristos 	} else {
37ba9bdd8bSchristos 		if (strlcat(ret, " nocbor,", retlen) >= retlen)
38ba9bdd8bSchristos 			goto toolong;
39ba9bdd8bSchristos 	}
40ba9bdd8bSchristos 
41ba9bdd8bSchristos 	if (flags & FIDO_CAP_NMSG) {
42ba9bdd8bSchristos 		if (strlcat(ret, " nomsg", retlen) >= retlen)
43ba9bdd8bSchristos 			goto toolong;
44ba9bdd8bSchristos 	} else {
45ba9bdd8bSchristos 		if (strlcat(ret, " msg", retlen) >= retlen)
46ba9bdd8bSchristos 			goto toolong;
47ba9bdd8bSchristos 	}
48ba9bdd8bSchristos 
49ba9bdd8bSchristos 	return;
50ba9bdd8bSchristos toolong:
51ba9bdd8bSchristos 	strlcpy(ret, "toolong", retlen);
52ba9bdd8bSchristos }
53ba9bdd8bSchristos 
54ba9bdd8bSchristos /*
55ba9bdd8bSchristos  * Print a FIDO device's attributes on stdout.
56ba9bdd8bSchristos  */
57ba9bdd8bSchristos static void
print_attr(const fido_dev_t * dev)58ba9bdd8bSchristos print_attr(const fido_dev_t *dev)
59ba9bdd8bSchristos {
60ba9bdd8bSchristos 	char flags_txt[128];
61ba9bdd8bSchristos 
62ba9bdd8bSchristos 	printf("proto: 0x%02x\n", fido_dev_protocol(dev));
63ba9bdd8bSchristos 	printf("major: 0x%02x\n", fido_dev_major(dev));
64ba9bdd8bSchristos 	printf("minor: 0x%02x\n", fido_dev_minor(dev));
65ba9bdd8bSchristos 	printf("build: 0x%02x\n", fido_dev_build(dev));
66ba9bdd8bSchristos 
67ba9bdd8bSchristos 	format_flags(flags_txt, sizeof(flags_txt), fido_dev_flags(dev));
68ba9bdd8bSchristos 	printf("caps: 0x%02x (%s)\n", fido_dev_flags(dev), flags_txt);
69ba9bdd8bSchristos }
70ba9bdd8bSchristos 
71ba9bdd8bSchristos /*
72ba9bdd8bSchristos  * Auxiliary function to print an array of strings on stdout.
73ba9bdd8bSchristos  */
74ba9bdd8bSchristos static void
print_str_array(const char * label,char * const * sa,size_t len)75ba9bdd8bSchristos print_str_array(const char *label, char * const *sa, size_t len)
76ba9bdd8bSchristos {
77ba9bdd8bSchristos 	if (len == 0)
78ba9bdd8bSchristos 		return;
79ba9bdd8bSchristos 
80ba9bdd8bSchristos 	printf("%s strings: ", label);
81ba9bdd8bSchristos 
82ba9bdd8bSchristos 	for (size_t i = 0; i < len; i++)
83ba9bdd8bSchristos 		printf("%s%s", i > 0 ? ", " : "", sa[i]);
84ba9bdd8bSchristos 
85ba9bdd8bSchristos 	printf("\n");
86ba9bdd8bSchristos }
87ba9bdd8bSchristos 
88ba9bdd8bSchristos /*
89ba9bdd8bSchristos  * Auxiliary function to print (char *, bool) pairs on stdout.
90ba9bdd8bSchristos  */
91ba9bdd8bSchristos static void
print_opt_array(const char * label,char * const * name,const bool * value,size_t len)92ba9bdd8bSchristos print_opt_array(const char *label, char * const *name, const bool *value,
93ba9bdd8bSchristos     size_t len)
94ba9bdd8bSchristos {
95ba9bdd8bSchristos 	if (len == 0)
96ba9bdd8bSchristos 		return;
97ba9bdd8bSchristos 
98ba9bdd8bSchristos 	printf("%s: ", label);
99ba9bdd8bSchristos 
100ba9bdd8bSchristos 	for (size_t i = 0; i < len; i++)
101ba9bdd8bSchristos 		printf("%s%s%s", i > 0 ? ", " : "",
102ba9bdd8bSchristos 		    value[i] ? "" : "no", name[i]);
103ba9bdd8bSchristos 
104ba9bdd8bSchristos 	printf("\n");
105ba9bdd8bSchristos }
106ba9bdd8bSchristos 
107ba9bdd8bSchristos /*
108*2d40c451Schristos  * Auxiliary function to print (char *, uint64_t) pairs on stdout.
109*2d40c451Schristos  */
110*2d40c451Schristos static void
print_cert_array(const char * label,char * const * name,const uint64_t * value,size_t len)111*2d40c451Schristos print_cert_array(const char *label, char * const *name, const uint64_t *value,
112*2d40c451Schristos     size_t len)
113*2d40c451Schristos {
114*2d40c451Schristos 	if (len == 0)
115*2d40c451Schristos 		return;
116*2d40c451Schristos 
117*2d40c451Schristos 	printf("%s: ", label);
118*2d40c451Schristos 
119*2d40c451Schristos 	for (size_t i = 0; i < len; i++)
120*2d40c451Schristos 		printf("%s%s %llu", i > 0 ? ", " : "", name[i],
121*2d40c451Schristos 		    (unsigned long long)value[i]);
122*2d40c451Schristos 
123*2d40c451Schristos 	printf("\n");
124*2d40c451Schristos }
125*2d40c451Schristos 
126*2d40c451Schristos /*
127ede6d7f8Schristos  * Auxiliary function to print a list of supported COSE algorithms on stdout.
128ede6d7f8Schristos  */
129ede6d7f8Schristos static void
print_algorithms(const fido_cbor_info_t * ci)130ede6d7f8Schristos print_algorithms(const fido_cbor_info_t *ci)
131ede6d7f8Schristos {
132ede6d7f8Schristos 	const char *cose, *type;
133ede6d7f8Schristos 	size_t len;
134ede6d7f8Schristos 
135ede6d7f8Schristos 	if ((len = fido_cbor_info_algorithm_count(ci)) == 0)
136ede6d7f8Schristos 		return;
137ede6d7f8Schristos 
138ede6d7f8Schristos 	printf("algorithms: ");
139ede6d7f8Schristos 
140ede6d7f8Schristos 	for (size_t i = 0; i < len; i++) {
141ede6d7f8Schristos 		cose = type = "unknown";
142ede6d7f8Schristos 		switch (fido_cbor_info_algorithm_cose(ci, i)) {
143ede6d7f8Schristos 		case COSE_ES256:
144ede6d7f8Schristos 			cose = "es256";
145ede6d7f8Schristos 			break;
146*2d40c451Schristos 		case COSE_ES384:
147*2d40c451Schristos 			cose = "es384";
148*2d40c451Schristos 			break;
149ede6d7f8Schristos 		case COSE_RS256:
150ede6d7f8Schristos 			cose = "rs256";
151ede6d7f8Schristos 			break;
152*2d40c451Schristos 		case COSE_EDDSA:
153*2d40c451Schristos 			cose = "eddsa";
154*2d40c451Schristos 			break;
155ede6d7f8Schristos 		}
156ede6d7f8Schristos 		if (fido_cbor_info_algorithm_type(ci, i) != NULL)
157ede6d7f8Schristos 			type = fido_cbor_info_algorithm_type(ci, i);
158ede6d7f8Schristos 		printf("%s%s (%s)", i > 0 ? ", " : "", cose, type);
159ede6d7f8Schristos 	}
160ede6d7f8Schristos 
161ede6d7f8Schristos 	printf("\n");
162ede6d7f8Schristos }
163ede6d7f8Schristos 
164ede6d7f8Schristos /*
165ba9bdd8bSchristos  * Auxiliary function to print an authenticator's AAGUID on stdout.
166ba9bdd8bSchristos  */
167ba9bdd8bSchristos static void
print_aaguid(const unsigned char * buf,size_t buflen)168ba9bdd8bSchristos print_aaguid(const unsigned char *buf, size_t buflen)
169ba9bdd8bSchristos {
170ba9bdd8bSchristos 	printf("aaguid: ");
171ba9bdd8bSchristos 
172ba9bdd8bSchristos 	while (buflen--)
173ba9bdd8bSchristos 		printf("%02x", *buf++);
174ba9bdd8bSchristos 
175ba9bdd8bSchristos 	printf("\n");
176ba9bdd8bSchristos }
177ba9bdd8bSchristos 
178ba9bdd8bSchristos /*
179ba9bdd8bSchristos  * Auxiliary function to print an authenticator's maximum message size on
180ba9bdd8bSchristos  * stdout.
181ba9bdd8bSchristos  */
182ba9bdd8bSchristos static void
print_maxmsgsiz(uint64_t maxmsgsiz)183ba9bdd8bSchristos print_maxmsgsiz(uint64_t maxmsgsiz)
184ba9bdd8bSchristos {
185ba9bdd8bSchristos 	printf("maxmsgsiz: %d\n", (int)maxmsgsiz);
186ba9bdd8bSchristos }
187ba9bdd8bSchristos 
188ba9bdd8bSchristos /*
1891fc1e710Schristos  * Auxiliary function to print an authenticator's maximum number of credentials
1901fc1e710Schristos  * in a credential list on stdout.
1911fc1e710Schristos  */
1921fc1e710Schristos static void
print_maxcredcntlst(uint64_t maxcredcntlst)1931fc1e710Schristos print_maxcredcntlst(uint64_t maxcredcntlst)
1941fc1e710Schristos {
1951fc1e710Schristos 	printf("maxcredcntlst: %d\n", (int)maxcredcntlst);
1961fc1e710Schristos }
1971fc1e710Schristos 
1981fc1e710Schristos /*
1991fc1e710Schristos  * Auxiliary function to print an authenticator's maximum credential ID length
2001fc1e710Schristos  * on stdout.
2011fc1e710Schristos  */
2021fc1e710Schristos static void
print_maxcredidlen(uint64_t maxcredidlen)2031fc1e710Schristos print_maxcredidlen(uint64_t maxcredidlen)
2041fc1e710Schristos {
2051fc1e710Schristos 	printf("maxcredlen: %d\n", (int)maxcredidlen);
2061fc1e710Schristos }
2071fc1e710Schristos 
2081fc1e710Schristos /*
209*2d40c451Schristos  * Auxiliary function to print the maximum size of an authenticator's
210*2d40c451Schristos  * serialized largeBlob array.
211*2d40c451Schristos  */
212*2d40c451Schristos static void
print_maxlargeblob(uint64_t maxlargeblob)213*2d40c451Schristos print_maxlargeblob(uint64_t maxlargeblob)
214*2d40c451Schristos {
215*2d40c451Schristos 	printf("maxlargeblob: %d\n", (int)maxlargeblob);
216*2d40c451Schristos }
217*2d40c451Schristos 
218*2d40c451Schristos /*
219*2d40c451Schristos  * Auxiliary function to print the authenticator's estimated number of
220*2d40c451Schristos  * remaining resident credentials.
221*2d40c451Schristos  */
222*2d40c451Schristos static void
print_rk_remaining(int64_t rk_remaining)223*2d40c451Schristos print_rk_remaining(int64_t rk_remaining)
224*2d40c451Schristos {
225*2d40c451Schristos 	printf("remaining rk(s): ");
226*2d40c451Schristos 
227*2d40c451Schristos 	if (rk_remaining == -1)
228*2d40c451Schristos 		printf("undefined\n");
229*2d40c451Schristos 	else
230*2d40c451Schristos 		printf("%d\n", (int)rk_remaining);
231*2d40c451Schristos }
232*2d40c451Schristos 
233*2d40c451Schristos /*
234*2d40c451Schristos  * Auxiliary function to print the minimum pin length observed by the
235*2d40c451Schristos  * authenticator.
236*2d40c451Schristos  */
237*2d40c451Schristos static void
print_minpinlen(uint64_t minpinlen)238*2d40c451Schristos print_minpinlen(uint64_t minpinlen)
239*2d40c451Schristos {
240*2d40c451Schristos 	printf("minpinlen: %d\n", (int)minpinlen);
241*2d40c451Schristos }
242*2d40c451Schristos 
243*2d40c451Schristos /*
244*2d40c451Schristos  * Auxiliary function to print the authenticator's preferred (platform)
245*2d40c451Schristos  * UV attempts.
246*2d40c451Schristos  */
247*2d40c451Schristos static void
print_uv_attempts(uint64_t uv_attempts)248*2d40c451Schristos print_uv_attempts(uint64_t uv_attempts)
249*2d40c451Schristos {
250*2d40c451Schristos 	printf("platform uv attempt(s): %d\n", (int)uv_attempts);
251*2d40c451Schristos }
252*2d40c451Schristos 
253*2d40c451Schristos /*
2541fc1e710Schristos  * Auxiliary function to print an authenticator's firmware version on stdout.
2551fc1e710Schristos  */
2561fc1e710Schristos static void
print_fwversion(uint64_t fwversion)2571fc1e710Schristos print_fwversion(uint64_t fwversion)
2581fc1e710Schristos {
2591fc1e710Schristos 	printf("fwversion: 0x%x\n", (int)fwversion);
2601fc1e710Schristos }
2611fc1e710Schristos 
2621fc1e710Schristos /*
263ba9bdd8bSchristos  * Auxiliary function to print an array of bytes on stdout.
264ba9bdd8bSchristos  */
265ba9bdd8bSchristos static void
print_byte_array(const char * label,const uint8_t * ba,size_t len)266ba9bdd8bSchristos print_byte_array(const char *label, const uint8_t *ba, size_t len)
267ba9bdd8bSchristos {
268ba9bdd8bSchristos 	if (len == 0)
269ba9bdd8bSchristos 		return;
270ba9bdd8bSchristos 
271ba9bdd8bSchristos 	printf("%s: ", label);
272ba9bdd8bSchristos 
273ba9bdd8bSchristos 	for (size_t i = 0; i < len; i++)
274ba9bdd8bSchristos 		printf("%s%u", i > 0 ? ", " : "", (unsigned)ba[i]);
275ba9bdd8bSchristos 
276ba9bdd8bSchristos 	printf("\n");
277ba9bdd8bSchristos }
278ba9bdd8bSchristos 
279ba9bdd8bSchristos static void
getinfo(const char * path)280ba9bdd8bSchristos getinfo(const char *path)
281ba9bdd8bSchristos {
282ba9bdd8bSchristos 	fido_dev_t		*dev;
283ba9bdd8bSchristos 	fido_cbor_info_t	*ci;
284ba9bdd8bSchristos 	int			 r;
285ba9bdd8bSchristos 
286ba9bdd8bSchristos 	fido_init(0);
287ba9bdd8bSchristos 
288ba9bdd8bSchristos 	if ((dev = fido_dev_new()) == NULL)
289ba9bdd8bSchristos 		errx(1, "fido_dev_new");
290ba9bdd8bSchristos 	if ((r = fido_dev_open(dev, path)) != FIDO_OK)
291ba9bdd8bSchristos 		errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r);
292ba9bdd8bSchristos 
293ba9bdd8bSchristos 	print_attr(dev);
294ba9bdd8bSchristos 
295ba9bdd8bSchristos 	if (fido_dev_is_fido2(dev) == false)
296ba9bdd8bSchristos 		goto end;
297ba9bdd8bSchristos 	if ((ci = fido_cbor_info_new()) == NULL)
298ba9bdd8bSchristos 		errx(1, "fido_cbor_info_new");
299ba9bdd8bSchristos 	if ((r = fido_dev_get_cbor_info(dev, ci)) != FIDO_OK)
300ba9bdd8bSchristos 		errx(1, "fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r);
301ba9bdd8bSchristos 
302ba9bdd8bSchristos 	/* print supported protocol versions */
303ba9bdd8bSchristos 	print_str_array("version", fido_cbor_info_versions_ptr(ci),
304ba9bdd8bSchristos 	    fido_cbor_info_versions_len(ci));
305ba9bdd8bSchristos 
306ba9bdd8bSchristos 	/* print supported extensions */
307ba9bdd8bSchristos 	print_str_array("extension", fido_cbor_info_extensions_ptr(ci),
308ba9bdd8bSchristos 	    fido_cbor_info_extensions_len(ci));
309ba9bdd8bSchristos 
310ede6d7f8Schristos 	/* print supported transports */
311ede6d7f8Schristos 	print_str_array("transport", fido_cbor_info_transports_ptr(ci),
312ede6d7f8Schristos 	    fido_cbor_info_transports_len(ci));
313ede6d7f8Schristos 
314ede6d7f8Schristos 	/* print supported algorithms */
315ede6d7f8Schristos 	print_algorithms(ci);
316ede6d7f8Schristos 
317ba9bdd8bSchristos 	/* print aaguid */
318ba9bdd8bSchristos 	print_aaguid(fido_cbor_info_aaguid_ptr(ci),
319ba9bdd8bSchristos 	    fido_cbor_info_aaguid_len(ci));
320ba9bdd8bSchristos 
321ba9bdd8bSchristos 	/* print supported options */
322ba9bdd8bSchristos 	print_opt_array("options", fido_cbor_info_options_name_ptr(ci),
323ba9bdd8bSchristos 	    fido_cbor_info_options_value_ptr(ci),
324ba9bdd8bSchristos 	    fido_cbor_info_options_len(ci));
325ba9bdd8bSchristos 
326*2d40c451Schristos 	/* print certifications */
327*2d40c451Schristos 	print_cert_array("certifications", fido_cbor_info_certs_name_ptr(ci),
328*2d40c451Schristos 	    fido_cbor_info_certs_value_ptr(ci),
329*2d40c451Schristos 	    fido_cbor_info_certs_len(ci));
330*2d40c451Schristos 
331*2d40c451Schristos 	/* print firmware version */
332*2d40c451Schristos 	print_fwversion(fido_cbor_info_fwversion(ci));
333*2d40c451Schristos 
334ba9bdd8bSchristos 	/* print maximum message size */
335ba9bdd8bSchristos 	print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci));
336ba9bdd8bSchristos 
3371fc1e710Schristos 	/* print maximum number of credentials allowed in credential lists */
3381fc1e710Schristos 	print_maxcredcntlst(fido_cbor_info_maxcredcntlst(ci));
3391fc1e710Schristos 
3401fc1e710Schristos 	/* print maximum length of a credential ID */
3411fc1e710Schristos 	print_maxcredidlen(fido_cbor_info_maxcredidlen(ci));
3421fc1e710Schristos 
343*2d40c451Schristos 	/* print maximum length of largeBlob array */
344*2d40c451Schristos 	print_maxlargeblob(fido_cbor_info_maxlargeblob(ci));
345*2d40c451Schristos 
346*2d40c451Schristos 	/* print number of remaining resident credentials */
347*2d40c451Schristos 	print_rk_remaining(fido_cbor_info_rk_remaining(ci));
348*2d40c451Schristos 
349*2d40c451Schristos 	/* print minimum pin length */
350*2d40c451Schristos 	print_minpinlen(fido_cbor_info_minpinlen(ci));
3511fc1e710Schristos 
352ba9bdd8bSchristos 	/* print supported pin protocols */
353ba9bdd8bSchristos 	print_byte_array("pin protocols", fido_cbor_info_protocols_ptr(ci),
354ba9bdd8bSchristos 	    fido_cbor_info_protocols_len(ci));
355ba9bdd8bSchristos 
356*2d40c451Schristos 	/* print whether a new pin is required */
357*2d40c451Schristos 	printf("pin change required: %s\n",
358*2d40c451Schristos 	    fido_cbor_info_new_pin_required(ci) ? "true" : "false");
359*2d40c451Schristos 
360*2d40c451Schristos 	/* print platform uv attempts */
361*2d40c451Schristos 	print_uv_attempts(fido_cbor_info_uv_attempts(ci));
362*2d40c451Schristos 
363ba9bdd8bSchristos 	fido_cbor_info_free(&ci);
364ba9bdd8bSchristos end:
365ba9bdd8bSchristos 	if ((r = fido_dev_close(dev)) != FIDO_OK)
366ba9bdd8bSchristos 		errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r);
367ba9bdd8bSchristos 
368ba9bdd8bSchristos 	fido_dev_free(&dev);
369ba9bdd8bSchristos }
370ba9bdd8bSchristos 
371ba9bdd8bSchristos int
main(int argc,char ** argv)372ba9bdd8bSchristos main(int argc, char **argv)
373ba9bdd8bSchristos {
374ba9bdd8bSchristos 	if (argc != 2) {
375ba9bdd8bSchristos 		fprintf(stderr, "usage: info <device>\n");
376ba9bdd8bSchristos 		exit(EXIT_FAILURE);
377ba9bdd8bSchristos 	}
378ba9bdd8bSchristos 
379ba9bdd8bSchristos 	getinfo(argv[1]);
380ba9bdd8bSchristos 
381ba9bdd8bSchristos 	exit(0);
382ba9bdd8bSchristos }
383