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 <openssl/ec.h> 8 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 #include "fido.h" 18 19 /* 20 * Pretty-print a device's capabilities flags and return the result. 21 */ 22 static void 23 format_flags(char *ret, size_t retlen, uint8_t flags) 24 { 25 memset(ret, 0, retlen); 26 27 if (flags & FIDO_CAP_WINK) { 28 if (strlcat(ret, "wink,", retlen) >= retlen) 29 goto toolong; 30 } else { 31 if (strlcat(ret, "nowink,", retlen) >= retlen) 32 goto toolong; 33 } 34 35 if (flags & FIDO_CAP_CBOR) { 36 if (strlcat(ret, " cbor,", retlen) >= retlen) 37 goto toolong; 38 } else { 39 if (strlcat(ret, " nocbor,", retlen) >= retlen) 40 goto toolong; 41 } 42 43 if (flags & FIDO_CAP_NMSG) { 44 if (strlcat(ret, " nomsg", retlen) >= retlen) 45 goto toolong; 46 } else { 47 if (strlcat(ret, " msg", retlen) >= retlen) 48 goto toolong; 49 } 50 51 return; 52 toolong: 53 strlcpy(ret, "toolong", retlen); 54 } 55 56 /* 57 * Print a FIDO device's attributes on stdout. 58 */ 59 static void 60 print_attr(const fido_dev_t *dev) 61 { 62 char flags_txt[128]; 63 64 printf("proto: 0x%02x\n", fido_dev_protocol(dev)); 65 printf("major: 0x%02x\n", fido_dev_major(dev)); 66 printf("minor: 0x%02x\n", fido_dev_minor(dev)); 67 printf("build: 0x%02x\n", fido_dev_build(dev)); 68 69 format_flags(flags_txt, sizeof(flags_txt), fido_dev_flags(dev)); 70 printf("caps: 0x%02x (%s)\n", fido_dev_flags(dev), flags_txt); 71 } 72 73 /* 74 * Auxiliary function to print an array of strings on stdout. 75 */ 76 static void 77 print_str_array(const char *label, char * const *sa, size_t len) 78 { 79 if (len == 0) 80 return; 81 82 printf("%s strings: ", label); 83 84 for (size_t i = 0; i < len; i++) 85 printf("%s%s", i > 0 ? ", " : "", sa[i]); 86 87 printf("\n"); 88 } 89 90 /* 91 * Auxiliary function to print (char *, bool) pairs on stdout. 92 */ 93 static void 94 print_opt_array(const char *label, char * const *name, const bool *value, 95 size_t len) 96 { 97 if (len == 0) 98 return; 99 100 printf("%s: ", label); 101 102 for (size_t i = 0; i < len; i++) 103 printf("%s%s%s", i > 0 ? ", " : "", 104 value[i] ? "" : "no", name[i]); 105 106 printf("\n"); 107 } 108 109 /* 110 * Auxiliary function to print an authenticator's AAGUID on stdout. 111 */ 112 static void 113 print_aaguid(const unsigned char *buf, size_t buflen) 114 { 115 printf("aaguid: "); 116 117 while (buflen--) 118 printf("%02x", *buf++); 119 120 printf("\n"); 121 } 122 123 /* 124 * Auxiliary function to print an authenticator's maximum message size on 125 * stdout. 126 */ 127 static void 128 print_maxmsgsiz(uint64_t maxmsgsiz) 129 { 130 printf("maxmsgsiz: %d\n", (int)maxmsgsiz); 131 } 132 133 /* 134 * Auxiliary function to print an array of bytes on stdout. 135 */ 136 static void 137 print_byte_array(const char *label, const uint8_t *ba, size_t len) 138 { 139 if (len == 0) 140 return; 141 142 printf("%s: ", label); 143 144 for (size_t i = 0; i < len; i++) 145 printf("%s%u", i > 0 ? ", " : "", (unsigned)ba[i]); 146 147 printf("\n"); 148 } 149 150 static void 151 getinfo(const char *path) 152 { 153 fido_dev_t *dev; 154 fido_cbor_info_t *ci; 155 int r; 156 157 fido_init(0); 158 159 if ((dev = fido_dev_new()) == NULL) 160 errx(1, "fido_dev_new"); 161 if ((r = fido_dev_open(dev, path)) != FIDO_OK) 162 errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); 163 164 print_attr(dev); 165 166 if (fido_dev_is_fido2(dev) == false) 167 goto end; 168 if ((ci = fido_cbor_info_new()) == NULL) 169 errx(1, "fido_cbor_info_new"); 170 if ((r = fido_dev_get_cbor_info(dev, ci)) != FIDO_OK) 171 errx(1, "fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r); 172 173 /* print supported protocol versions */ 174 print_str_array("version", fido_cbor_info_versions_ptr(ci), 175 fido_cbor_info_versions_len(ci)); 176 177 /* print supported extensions */ 178 print_str_array("extension", fido_cbor_info_extensions_ptr(ci), 179 fido_cbor_info_extensions_len(ci)); 180 181 /* print aaguid */ 182 print_aaguid(fido_cbor_info_aaguid_ptr(ci), 183 fido_cbor_info_aaguid_len(ci)); 184 185 /* print supported options */ 186 print_opt_array("options", fido_cbor_info_options_name_ptr(ci), 187 fido_cbor_info_options_value_ptr(ci), 188 fido_cbor_info_options_len(ci)); 189 190 /* print maximum message size */ 191 print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci)); 192 193 /* print supported pin protocols */ 194 print_byte_array("pin protocols", fido_cbor_info_protocols_ptr(ci), 195 fido_cbor_info_protocols_len(ci)); 196 197 fido_cbor_info_free(&ci); 198 end: 199 if ((r = fido_dev_close(dev)) != FIDO_OK) 200 errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); 201 202 fido_dev_free(&dev); 203 } 204 205 int 206 main(int argc, char **argv) 207 { 208 if (argc != 2) { 209 fprintf(stderr, "usage: info <device>\n"); 210 exit(EXIT_FAILURE); 211 } 212 213 getinfo(argv[1]); 214 215 exit(0); 216 } 217