1 /* 2 * Copyright (c) 2018 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 */ 6 7 #include <fido.h> 8 #include <stdbool.h> 9 #include <stdint.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 14 #include "../openbsd-compat/openbsd-compat.h" 15 16 /* 17 * Pretty-print a device's capabilities flags and return the result. 18 */ 19 static void 20 format_flags(char *ret, size_t retlen, uint8_t flags) 21 { 22 memset(ret, 0, retlen); 23 24 if (flags & FIDO_CAP_WINK) { 25 if (strlcat(ret, "wink,", retlen) >= retlen) 26 goto toolong; 27 } else { 28 if (strlcat(ret, "nowink,", retlen) >= retlen) 29 goto toolong; 30 } 31 32 if (flags & FIDO_CAP_CBOR) { 33 if (strlcat(ret, " cbor,", retlen) >= retlen) 34 goto toolong; 35 } else { 36 if (strlcat(ret, " nocbor,", retlen) >= retlen) 37 goto toolong; 38 } 39 40 if (flags & FIDO_CAP_NMSG) { 41 if (strlcat(ret, " nomsg", retlen) >= retlen) 42 goto toolong; 43 } else { 44 if (strlcat(ret, " msg", retlen) >= retlen) 45 goto toolong; 46 } 47 48 return; 49 toolong: 50 strlcpy(ret, "toolong", retlen); 51 } 52 53 /* 54 * Print a FIDO device's attributes on stdout. 55 */ 56 static void 57 print_attr(const fido_dev_t *dev) 58 { 59 char flags_txt[128]; 60 61 printf("proto: 0x%02x\n", fido_dev_protocol(dev)); 62 printf("major: 0x%02x\n", fido_dev_major(dev)); 63 printf("minor: 0x%02x\n", fido_dev_minor(dev)); 64 printf("build: 0x%02x\n", fido_dev_build(dev)); 65 66 format_flags(flags_txt, sizeof(flags_txt), fido_dev_flags(dev)); 67 printf("caps: 0x%02x (%s)\n", fido_dev_flags(dev), flags_txt); 68 } 69 70 /* 71 * Auxiliary function to print an array of strings on stdout. 72 */ 73 static void 74 print_str_array(const char *label, char * const *sa, size_t len) 75 { 76 if (len == 0) 77 return; 78 79 printf("%s strings: ", label); 80 81 for (size_t i = 0; i < len; i++) 82 printf("%s%s", i > 0 ? ", " : "", sa[i]); 83 84 printf("\n"); 85 } 86 87 /* 88 * Auxiliary function to print (char *, bool) pairs on stdout. 89 */ 90 static void 91 print_opt_array(const char *label, char * const *name, const bool *value, 92 size_t len) 93 { 94 if (len == 0) 95 return; 96 97 printf("%s: ", label); 98 99 for (size_t i = 0; i < len; i++) 100 printf("%s%s%s", i > 0 ? ", " : "", 101 value[i] ? "" : "no", name[i]); 102 103 printf("\n"); 104 } 105 106 /* 107 * Auxiliary function to print a list of supported COSE algorithms on stdout. 108 */ 109 static void 110 print_algorithms(const fido_cbor_info_t *ci) 111 { 112 const char *cose, *type; 113 size_t len; 114 115 if ((len = fido_cbor_info_algorithm_count(ci)) == 0) 116 return; 117 118 printf("algorithms: "); 119 120 for (size_t i = 0; i < len; i++) { 121 cose = type = "unknown"; 122 switch (fido_cbor_info_algorithm_cose(ci, i)) { 123 case COSE_EDDSA: 124 cose = "eddsa"; 125 break; 126 case COSE_ES256: 127 cose = "es256"; 128 break; 129 case COSE_RS256: 130 cose = "rs256"; 131 break; 132 } 133 if (fido_cbor_info_algorithm_type(ci, i) != NULL) 134 type = fido_cbor_info_algorithm_type(ci, i); 135 printf("%s%s (%s)", i > 0 ? ", " : "", cose, type); 136 } 137 138 printf("\n"); 139 } 140 141 /* 142 * Auxiliary function to print an authenticator's AAGUID on stdout. 143 */ 144 static void 145 print_aaguid(const unsigned char *buf, size_t buflen) 146 { 147 printf("aaguid: "); 148 149 while (buflen--) 150 printf("%02x", *buf++); 151 152 printf("\n"); 153 } 154 155 /* 156 * Auxiliary function to print an authenticator's maximum message size on 157 * stdout. 158 */ 159 static void 160 print_maxmsgsiz(uint64_t maxmsgsiz) 161 { 162 printf("maxmsgsiz: %d\n", (int)maxmsgsiz); 163 } 164 165 /* 166 * Auxiliary function to print an authenticator's maximum number of credentials 167 * in a credential list on stdout. 168 */ 169 static void 170 print_maxcredcntlst(uint64_t maxcredcntlst) 171 { 172 printf("maxcredcntlst: %d\n", (int)maxcredcntlst); 173 } 174 175 /* 176 * Auxiliary function to print an authenticator's maximum credential ID length 177 * on stdout. 178 */ 179 static void 180 print_maxcredidlen(uint64_t maxcredidlen) 181 { 182 printf("maxcredlen: %d\n", (int)maxcredidlen); 183 } 184 185 /* 186 * Auxiliary function to print an authenticator's firmware version on stdout. 187 */ 188 static void 189 print_fwversion(uint64_t fwversion) 190 { 191 printf("fwversion: 0x%x\n", (int)fwversion); 192 } 193 194 /* 195 * Auxiliary function to print an array of bytes on stdout. 196 */ 197 static void 198 print_byte_array(const char *label, const uint8_t *ba, size_t len) 199 { 200 if (len == 0) 201 return; 202 203 printf("%s: ", label); 204 205 for (size_t i = 0; i < len; i++) 206 printf("%s%u", i > 0 ? ", " : "", (unsigned)ba[i]); 207 208 printf("\n"); 209 } 210 211 static void 212 getinfo(const char *path) 213 { 214 fido_dev_t *dev; 215 fido_cbor_info_t *ci; 216 int r; 217 218 fido_init(0); 219 220 if ((dev = fido_dev_new()) == NULL) 221 errx(1, "fido_dev_new"); 222 if ((r = fido_dev_open(dev, path)) != FIDO_OK) 223 errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); 224 225 print_attr(dev); 226 227 if (fido_dev_is_fido2(dev) == false) 228 goto end; 229 if ((ci = fido_cbor_info_new()) == NULL) 230 errx(1, "fido_cbor_info_new"); 231 if ((r = fido_dev_get_cbor_info(dev, ci)) != FIDO_OK) 232 errx(1, "fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r); 233 234 /* print supported protocol versions */ 235 print_str_array("version", fido_cbor_info_versions_ptr(ci), 236 fido_cbor_info_versions_len(ci)); 237 238 /* print supported extensions */ 239 print_str_array("extension", fido_cbor_info_extensions_ptr(ci), 240 fido_cbor_info_extensions_len(ci)); 241 242 /* print supported transports */ 243 print_str_array("transport", fido_cbor_info_transports_ptr(ci), 244 fido_cbor_info_transports_len(ci)); 245 246 /* print supported algorithms */ 247 print_algorithms(ci); 248 249 /* print aaguid */ 250 print_aaguid(fido_cbor_info_aaguid_ptr(ci), 251 fido_cbor_info_aaguid_len(ci)); 252 253 /* print supported options */ 254 print_opt_array("options", fido_cbor_info_options_name_ptr(ci), 255 fido_cbor_info_options_value_ptr(ci), 256 fido_cbor_info_options_len(ci)); 257 258 /* print maximum message size */ 259 print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci)); 260 261 /* print maximum number of credentials allowed in credential lists */ 262 print_maxcredcntlst(fido_cbor_info_maxcredcntlst(ci)); 263 264 /* print maximum length of a credential ID */ 265 print_maxcredidlen(fido_cbor_info_maxcredidlen(ci)); 266 267 /* print firmware version */ 268 print_fwversion(fido_cbor_info_fwversion(ci)); 269 270 /* print supported pin protocols */ 271 print_byte_array("pin protocols", fido_cbor_info_protocols_ptr(ci), 272 fido_cbor_info_protocols_len(ci)); 273 274 fido_cbor_info_free(&ci); 275 end: 276 if ((r = fido_dev_close(dev)) != FIDO_OK) 277 errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); 278 279 fido_dev_free(&dev); 280 } 281 282 int 283 main(int argc, char **argv) 284 { 285 if (argc != 2) { 286 fprintf(stderr, "usage: info <device>\n"); 287 exit(EXIT_FAILURE); 288 } 289 290 getinfo(argv[1]); 291 292 exit(0); 293 } 294