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