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