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