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
format_flags(char * ret,size_t retlen,uint8_t flags)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
print_attr(const fido_dev_t * dev)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
print_str_array(const char * label,char * const * sa,size_t len)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
print_opt_array(const char * label,char * const * name,const bool * value,size_t len)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
print_cert_array(const char * label,char * const * name,const uint64_t * value,size_t len)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
print_algorithms(const fido_cbor_info_t * ci)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
print_aaguid(const unsigned char * buf,size_t buflen)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
print_maxmsgsiz(uint64_t maxmsgsiz)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
print_maxcredcntlst(uint64_t maxcredcntlst)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
print_maxcredidlen(uint64_t maxcredidlen)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
print_maxlargeblob(uint64_t maxlargeblob)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
print_rk_remaining(int64_t rk_remaining)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
print_minpinlen(uint64_t minpinlen)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
print_uv_attempts(uint64_t uv_attempts)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
print_fwversion(uint64_t fwversion)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
print_byte_array(const char * label,const uint8_t * ba,size_t len)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
getinfo(const char * path)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
main(int argc,char ** argv)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