| Line | Count | Source (jump to first uncovered line) | 
| 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 |  |  | 
| 10 |  | #ifndef TLS | 
| 11 |  | #define TLS | 
| 12 |  | #endif | 
| 13 |  |  | 
| 14 |  | static TLS bool disable_u2f_fallback; | 
| 15 |  |  | 
| 16 |  | #ifdef FIDO_FUZZ | 
| 17 |  | static void | 
| 18 |  | set_random_report_len(fido_dev_t *dev) | 
| 19 | 115k | { | 
| 20 | 115k |         dev->rx_len = CTAP_MIN_REPORT_LEN + | 
| 21 | 115k |             uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1); | 
| 22 | 115k |         dev->tx_len = CTAP_MIN_REPORT_LEN + | 
| 23 | 115k |             uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1); | 
| 24 | 115k | } | 
| 25 |  | #endif | 
| 26 |  |  | 
| 27 |  | static void | 
| 28 |  | fido_dev_set_extension_flags(fido_dev_t *dev, const fido_cbor_info_t *info) | 
| 29 | 12.5k | { | 
| 30 | 12.5k |         char * const    *ptr = fido_cbor_info_extensions_ptr(info); | 
| 31 | 12.5k |         size_t           len = fido_cbor_info_extensions_len(info); | 
| 32 |  |  | 
| 33 | 34.3k |         for (size_t i = 0; i < len; i++) | 
| 34 | 21.7k |                 if (strcmp(ptr[i], "credProtect") == 0) | 
| 35 | 5.80k |                         dev->flags |= FIDO_DEV_CRED_PROT; | 
| 36 | 12.5k | } | 
| 37 |  |  | 
| 38 |  | static void | 
| 39 |  | fido_dev_set_option_flags(fido_dev_t *dev, const fido_cbor_info_t *info) | 
| 40 | 12.5k | { | 
| 41 | 12.5k |         char * const    *ptr = fido_cbor_info_options_name_ptr(info); | 
| 42 | 12.5k |         const bool      *val = fido_cbor_info_options_value_ptr(info); | 
| 43 | 12.5k |         size_t           len = fido_cbor_info_options_len(info); | 
| 44 |  |  | 
| 45 | 65.4k |         for (size_t i = 0; i < len; i++) | 
| 46 | 52.8k |                 if (strcmp(ptr[i], "clientPin") == 0) { | 
| 47 | 5.72k |                         dev->flags |= val[i] ? | 
| 48 | 5.34k |                             FIDO_DEV_PIN_SET : FIDO_DEV_PIN_UNSET; | 
| 49 | 47.1k |                 } else if (strcmp(ptr[i], "credMgmt") == 0) { | 
| 50 | 296 |                         if (val[i]) | 
| 51 | 256 |                                 dev->flags |= FIDO_DEV_CREDMAN; | 
| 52 | 46.8k |                 } else if (strcmp(ptr[i], "credentialMgmtPreview") == 0) { | 
| 53 | 4.07k |                         if (val[i]) | 
| 54 | 4.03k |                                 dev->flags |= FIDO_DEV_CREDMAN_PRE; | 
| 55 | 42.7k |                 } else if (strcmp(ptr[i], "uv") == 0) { | 
| 56 | 544 |                         dev->flags |= val[i] ? | 
| 57 | 524 |                             FIDO_DEV_UV_SET : FIDO_DEV_UV_UNSET; | 
| 58 | 42.1k |                 } else if (strcmp(ptr[i], "pinUvAuthToken") == 0) { | 
| 59 | 374 |                         if (val[i]) | 
| 60 | 346 |                                 dev->flags |= FIDO_DEV_TOKEN_PERMS; | 
| 61 | 41.8k |                 } else if (strcmp(ptr[i], "bioEnroll") == 0) { | 
| 62 | 285 |                         dev->flags |= val[i] ? | 
| 63 | 249 |                             FIDO_DEV_BIO_SET : FIDO_DEV_BIO_UNSET; | 
| 64 | 285 |                 } | 
| 65 | 12.5k | } | 
| 66 |  |  | 
| 67 |  | static void | 
| 68 |  | fido_dev_set_protocol_flags(fido_dev_t *dev, const fido_cbor_info_t *info) | 
| 69 | 12.5k | { | 
| 70 | 12.5k |         const uint8_t   *ptr = fido_cbor_info_protocols_ptr(info); | 
| 71 | 12.5k |         size_t           len = fido_cbor_info_protocols_len(info); | 
| 72 |  |  | 
| 73 | 25.8k |         for (size_t i = 0; i < len; i++) | 
| 74 | 13.2k |                 switch (ptr[i]) { | 
| 75 | 9.96k |                 case CTAP_PIN_PROTOCOL1: | 
| 76 | 9.96k |                         dev->flags |= FIDO_DEV_PIN_PROTOCOL1; | 
| 77 | 9.96k |                         break; | 
| 78 | 1.92k |                 case CTAP_PIN_PROTOCOL2: | 
| 79 | 1.92k |                         dev->flags |= FIDO_DEV_PIN_PROTOCOL2; | 
| 80 | 1.92k |                         break; | 
| 81 | 1.38k |                 default: | 
| 82 | 1.38k |                         fido_log_debug("%s: unknown protocol %u", __func__, | 
| 83 | 1.38k |                             ptr[i]); | 
| 84 | 1.38k |                         break; | 
| 85 | 13.2k |                 } | 
| 86 | 12.5k | } | 
| 87 |  |  | 
| 88 |  | static void | 
| 89 |  | fido_dev_set_flags(fido_dev_t *dev, const fido_cbor_info_t *info) | 
| 90 | 12.5k | { | 
| 91 | 12.5k |         fido_dev_set_extension_flags(dev, info); | 
| 92 | 12.5k |         fido_dev_set_option_flags(dev, info); | 
| 93 | 12.5k |         fido_dev_set_protocol_flags(dev, info); | 
| 94 | 12.5k | } | 
| 95 |  |  | 
| 96 |  | static int | 
| 97 |  | fido_dev_open_tx(fido_dev_t *dev, const char *path, int *ms) | 
| 98 | 849k | { | 
| 99 | 849k |         int r; | 
| 100 |  |  | 
| 101 | 849k |         if (dev->io_handle != NULL) { | 
| 102 | 0 |                 fido_log_debug("%s: handle=%p", __func__, dev->io_handle); | 
| 103 | 0 |                 return (FIDO_ERR_INVALID_ARGUMENT); | 
| 104 | 0 |         } | 
| 105 |  |  | 
| 106 | 849k |         if (dev->io.open == NULL || dev->io.close == NULL) { | 
| 107 | 0 |                 fido_log_debug("%s: NULL open/close", __func__); | 
| 108 | 0 |                 return (FIDO_ERR_INVALID_ARGUMENT); | 
| 109 | 0 |         } | 
| 110 |  |  | 
| 111 | 849k |         if (dev->cid != CTAP_CID_BROADCAST) { | 
| 112 | 0 |                 fido_log_debug("%s: cid=0x%x", __func__, dev->cid); | 
| 113 | 0 |                 return (FIDO_ERR_INVALID_ARGUMENT); | 
| 114 | 0 |         } | 
| 115 |  |  | 
| 116 | 849k |         if (fido_get_random(&dev->nonce, sizeof(dev->nonce)) < 0) { | 
| 117 | 2.07k |                 fido_log_debug("%s: fido_get_random", __func__); | 
| 118 | 2.07k |                 return (FIDO_ERR_INTERNAL); | 
| 119 | 2.07k |         } | 
| 120 |  |  | 
| 121 | 847k |         if ((dev->io_handle = dev->io.open(path)) == NULL) { | 
| 122 | 731k |                 fido_log_debug("%s: dev->io.open", __func__); | 
| 123 | 731k |                 return (FIDO_ERR_INTERNAL); | 
| 124 | 731k |         } | 
| 125 |  |  | 
| 126 | 115k |         if (dev->io_own) { | 
| 127 | 115k |                 dev->rx_len = CTAP_MAX_REPORT_LEN; | 
| 128 | 115k |                 dev->tx_len = CTAP_MAX_REPORT_LEN; | 
| 129 | 115k |         } else { | 
| 130 | 0 |                 dev->rx_len = fido_hid_report_in_len(dev->io_handle); | 
| 131 | 0 |                 dev->tx_len = fido_hid_report_out_len(dev->io_handle); | 
| 132 | 0 |         } | 
| 133 |  |  | 
| 134 | 115k | #ifdef FIDO_FUZZ | 
| 135 | 115k |         set_random_report_len(dev); | 
| 136 | 115k | #endif | 
| 137 |  |  | 
| 138 | 115k |         if (dev->rx_len < CTAP_MIN_REPORT_LEN || | 
| 139 | 115k |             dev->rx_len > CTAP_MAX_REPORT_LEN) { | 
| 140 | 0 |                 fido_log_debug("%s: invalid rx_len %zu", __func__, dev->rx_len); | 
| 141 | 0 |                 r = FIDO_ERR_RX; | 
| 142 | 0 |                 goto fail; | 
| 143 | 0 |         } | 
| 144 |  |  | 
| 145 | 115k |         if (dev->tx_len < CTAP_MIN_REPORT_LEN || | 
| 146 | 115k |             dev->tx_len > CTAP_MAX_REPORT_LEN) { | 
| 147 | 0 |                 fido_log_debug("%s: invalid tx_len %zu", __func__, dev->tx_len); | 
| 148 | 0 |                 r = FIDO_ERR_TX; | 
| 149 | 0 |                 goto fail; | 
| 150 | 0 |         } | 
| 151 |  |  | 
| 152 | 115k |         if (fido_tx(dev, CTAP_CMD_INIT, &dev->nonce, sizeof(dev->nonce), | 
| 153 | 115k |             ms) < 0) { | 
| 154 | 2.12k |                 fido_log_debug("%s: fido_tx", __func__); | 
| 155 | 2.12k |                 r = FIDO_ERR_TX; | 
| 156 | 2.12k |                 goto fail; | 
| 157 | 2.12k |         } | 
| 158 |  |  | 
| 159 | 113k |         return (FIDO_OK); | 
| 160 | 2.12k | fail: | 
| 161 | 2.12k |         dev->io.close(dev->io_handle); | 
| 162 | 2.12k |         dev->io_handle = NULL; | 
| 163 |  |  | 
| 164 | 2.12k |         return (r); | 
| 165 | 115k | } | 
| 166 |  |  | 
| 167 |  | static int | 
| 168 |  | fido_dev_open_rx(fido_dev_t *dev, int *ms) | 
| 169 | 113k | { | 
| 170 | 113k |         fido_cbor_info_t        *info = NULL; | 
| 171 | 113k |         int                      reply_len; | 
| 172 | 113k |         int                      r; | 
| 173 |  |  | 
| 174 | 113k |         if ((reply_len = fido_rx(dev, CTAP_CMD_INIT, &dev->attr, | 
| 175 | 113k |             sizeof(dev->attr), ms)) < 0) { | 
| 176 | 65.4k |                 fido_log_debug("%s: fido_rx", __func__); | 
| 177 | 65.4k |                 r = FIDO_ERR_RX; | 
| 178 | 65.4k |                 goto fail; | 
| 179 | 65.4k |         } | 
| 180 |  |  | 
| 181 | 48.2k | #ifdef FIDO_FUZZ | 
| 182 | 48.2k |         dev->attr.nonce = dev->nonce; | 
| 183 | 48.2k | #endif | 
| 184 |  |  | 
| 185 | 48.2k |         if ((size_t)reply_len != sizeof(dev->attr) || | 
| 186 | 48.2k |             dev->attr.nonce != dev->nonce) { | 
| 187 | 1.46k |                 fido_log_debug("%s: invalid nonce", __func__); | 
| 188 | 1.46k |                 r = FIDO_ERR_RX; | 
| 189 | 1.46k |                 goto fail; | 
| 190 | 1.46k |         } | 
| 191 |  |  | 
| 192 | 46.7k |         dev->flags = 0; | 
| 193 | 46.7k |         dev->cid = dev->attr.cid; | 
| 194 |  |  | 
| 195 | 46.7k |         if (fido_dev_is_fido2(dev)) { | 
| 196 | 36.6k |                 if ((info = fido_cbor_info_new()) == NULL) { | 
| 197 | 116 |                         fido_log_debug("%s: fido_cbor_info_new", __func__); | 
| 198 | 116 |                         r = FIDO_ERR_INTERNAL; | 
| 199 | 116 |                         goto fail; | 
| 200 | 116 |                 } | 
| 201 | 36.5k |                 if ((r = fido_dev_get_cbor_info_wait(dev, info, | 
| 202 | 36.5k |                     ms)) != FIDO_OK) { | 
| 203 | 23.9k |                         fido_log_debug("%s: fido_dev_cbor_info_wait: %d", | 
| 204 | 23.9k |                             __func__, r); | 
| 205 | 23.9k |                         if (disable_u2f_fallback) | 
| 206 | 0 |                                 goto fail; | 
| 207 | 23.9k |                         fido_log_debug("%s: falling back to u2f", __func__); | 
| 208 | 23.9k |                         fido_dev_force_u2f(dev); | 
| 209 | 23.9k |                 } else { | 
| 210 | 12.5k |                         fido_dev_set_flags(dev, info); | 
| 211 | 12.5k |                 } | 
| 212 | 36.5k |         } | 
| 213 |  |  | 
| 214 | 46.6k |         if (fido_dev_is_fido2(dev) && info != NULL) { | 
| 215 | 12.5k |                 dev->maxmsgsize = fido_cbor_info_maxmsgsiz(info); | 
| 216 | 12.5k |                 fido_log_debug("%s: FIDO_MAXMSG=%d, maxmsgsiz=%lu", __func__, | 
| 217 | 12.5k |                     FIDO_MAXMSG, (unsigned long)dev->maxmsgsize); | 
| 218 | 12.5k |         } | 
| 219 |  |  | 
| 220 | 46.6k |         r = FIDO_OK; | 
| 221 | 113k | fail: | 
| 222 | 113k |         fido_cbor_info_free(&info); | 
| 223 |  |  | 
| 224 | 113k |         if (r != FIDO_OK) { | 
| 225 | 67.0k |                 dev->io.close(dev->io_handle); | 
| 226 | 67.0k |                 dev->io_handle = NULL; | 
| 227 | 67.0k |         } | 
| 228 |  |  | 
| 229 | 113k |         return (r); | 
| 230 | 46.6k | } | 
| 231 |  |  | 
| 232 |  | static int | 
| 233 |  | fido_dev_open_wait(fido_dev_t *dev, const char *path, int *ms) | 
| 234 | 849k | { | 
| 235 | 849k |         int r; | 
| 236 |  |  | 
| 237 |  | #ifdef USE_WINHELLO | 
| 238 |  |         if (strcmp(path, FIDO_WINHELLO_PATH) == 0) | 
| 239 |  |                 return (fido_winhello_open(dev)); | 
| 240 |  | #endif | 
| 241 | 849k |         if ((r = fido_dev_open_tx(dev, path, ms)) != FIDO_OK || | 
| 242 | 849k |             (r = fido_dev_open_rx(dev, ms)) != FIDO_OK) | 
| 243 | 802k |                 return (r); | 
| 244 |  |  | 
| 245 | 46.6k |         return (FIDO_OK); | 
| 246 | 849k | } | 
| 247 |  |  | 
| 248 |  | static void | 
| 249 |  | run_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen, | 
| 250 |  |     const char *type, int (*manifest)(fido_dev_info_t *, size_t, size_t *)) | 
| 251 | 5.01k | { | 
| 252 | 5.01k |         size_t ndevs = 0; | 
| 253 | 5.01k |         int r; | 
| 254 |  |  | 
| 255 | 5.01k |         if (*olen >= ilen) { | 
| 256 | 136 |                 fido_log_debug("%s: skipping %s", __func__, type); | 
| 257 | 136 |                 return; | 
| 258 | 136 |         } | 
| 259 | 4.88k |         if ((r = manifest(devlist + *olen, ilen - *olen, &ndevs)) != FIDO_OK) | 
| 260 | 45 |                 fido_log_debug("%s: %s: 0x%x", __func__, type, r); | 
| 261 | 4.88k |         fido_log_debug("%s: found %zu %s device%s", __func__, ndevs, type, | 
| 262 | 4.88k |             ndevs == 1 ? "" : "s"); | 
| 263 | 4.88k |         *olen += ndevs; | 
| 264 | 4.88k | } | 
| 265 |  |  | 
| 266 |  | int | 
| 267 |  | fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) | 
| 268 | 1.67k | { | 
| 269 | 1.67k |         *olen = 0; | 
| 270 |  |  | 
| 271 | 1.67k |         run_manifest(devlist, ilen, olen, "hid", fido_hid_manifest); | 
| 272 | 1.67k | #ifdef USE_NFC | 
| 273 | 1.67k |         run_manifest(devlist, ilen, olen, "nfc", fido_nfc_manifest); | 
| 274 | 1.67k | #endif | 
| 275 | 1.67k | #ifdef USE_PCSC | 
| 276 | 1.67k |         run_manifest(devlist, ilen, olen, "pcsc", fido_pcsc_manifest); | 
| 277 | 1.67k | #endif | 
| 278 |  | #ifdef USE_WINHELLO | 
| 279 |  |         run_manifest(devlist, ilen, olen, "winhello", fido_winhello_manifest); | 
| 280 |  | #endif | 
| 281 |  |  | 
| 282 | 1.67k |         return (FIDO_OK); | 
| 283 | 1.67k | } | 
| 284 |  |  | 
| 285 |  | int | 
| 286 |  | fido_dev_open_with_info(fido_dev_t *dev) | 
| 287 | 0 | { | 
| 288 | 0 |         int ms = dev->timeout_ms; | 
| 289 |  | 
 | 
| 290 | 0 |         if (dev->path == NULL) | 
| 291 | 0 |                 return (FIDO_ERR_INVALID_ARGUMENT); | 
| 292 |  |  | 
| 293 | 0 |         return (fido_dev_open_wait(dev, dev->path, &ms)); | 
| 294 | 0 | } | 
| 295 |  |  | 
| 296 |  | int | 
| 297 |  | fido_dev_open(fido_dev_t *dev, const char *path) | 
| 298 | 849k | { | 
| 299 | 849k |         int ms = dev->timeout_ms; | 
| 300 |  |  | 
| 301 | 849k | #ifdef USE_NFC | 
| 302 | 849k |         if (fido_is_nfc(path) && fido_dev_set_nfc(dev) < 0) { | 
| 303 | 0 |                 fido_log_debug("%s: fido_dev_set_nfc", __func__); | 
| 304 | 0 |                 return FIDO_ERR_INTERNAL; | 
| 305 | 0 |         } | 
| 306 | 849k | #endif | 
| 307 | 849k | #ifdef USE_PCSC | 
| 308 | 849k |         if (fido_is_pcsc(path) && fido_dev_set_pcsc(dev) < 0) { | 
| 309 | 0 |                 fido_log_debug("%s: fido_dev_set_pcsc", __func__); | 
| 310 | 0 |                 return FIDO_ERR_INTERNAL; | 
| 311 | 0 |         } | 
| 312 | 849k | #endif | 
| 313 |  |  | 
| 314 | 849k |         return (fido_dev_open_wait(dev, path, &ms)); | 
| 315 | 849k | } | 
| 316 |  |  | 
| 317 |  | int | 
| 318 |  | fido_dev_close(fido_dev_t *dev) | 
| 319 | 46.6k | { | 
| 320 |  | #ifdef USE_WINHELLO | 
| 321 |  |         if (dev->flags & FIDO_DEV_WINHELLO) | 
| 322 |  |                 return (fido_winhello_close(dev)); | 
| 323 |  | #endif | 
| 324 | 46.6k |         if (dev->io_handle == NULL || dev->io.close == NULL) | 
| 325 | 0 |                 return (FIDO_ERR_INVALID_ARGUMENT); | 
| 326 |  |  | 
| 327 | 46.6k |         dev->io.close(dev->io_handle); | 
| 328 | 46.6k |         dev->io_handle = NULL; | 
| 329 | 46.6k |         dev->cid = CTAP_CID_BROADCAST; | 
| 330 |  |  | 
| 331 | 46.6k |         return (FIDO_OK); | 
| 332 | 46.6k | } | 
| 333 |  |  | 
| 334 |  | int | 
| 335 |  | fido_dev_set_sigmask(fido_dev_t *dev, const fido_sigset_t *sigmask) | 
| 336 | 0 | { | 
| 337 | 0 |         if (dev->io_handle == NULL || sigmask == NULL) | 
| 338 | 0 |                 return (FIDO_ERR_INVALID_ARGUMENT); | 
| 339 |  |  | 
| 340 | 0 | #ifdef USE_NFC | 
| 341 | 0 |         if (dev->transport.rx == fido_nfc_rx && dev->io.read == fido_nfc_read) | 
| 342 | 0 |                 return (fido_nfc_set_sigmask(dev->io_handle, sigmask)); | 
| 343 | 0 | #endif | 
| 344 | 0 |         if (dev->transport.rx == NULL && dev->io.read == fido_hid_read) | 
| 345 | 0 |                 return (fido_hid_set_sigmask(dev->io_handle, sigmask)); | 
| 346 |  |  | 
| 347 | 0 |         return (FIDO_ERR_INVALID_ARGUMENT); | 
| 348 | 0 | } | 
| 349 |  |  | 
| 350 |  | int | 
| 351 |  | fido_dev_cancel(fido_dev_t *dev) | 
| 352 | 9.86k | { | 
| 353 | 9.86k |         int ms = dev->timeout_ms; | 
| 354 |  |  | 
| 355 |  | #ifdef USE_WINHELLO | 
| 356 |  |         if (dev->flags & FIDO_DEV_WINHELLO) | 
| 357 |  |                 return (fido_winhello_cancel(dev)); | 
| 358 |  | #endif | 
| 359 | 9.86k |         if (fido_dev_is_fido2(dev) == false) | 
| 360 | 6.56k |                 return (FIDO_ERR_INVALID_ARGUMENT); | 
| 361 | 3.30k |         if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0, &ms) < 0) | 
| 362 | 356 |                 return (FIDO_ERR_TX); | 
| 363 |  |  | 
| 364 | 2.95k |         return (FIDO_OK); | 
| 365 | 3.30k | } | 
| 366 |  |  | 
| 367 |  | int | 
| 368 |  | fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) | 
| 369 | 114k | { | 
| 370 | 114k |         if (dev->io_handle != NULL) { | 
| 371 | 0 |                 fido_log_debug("%s: non-NULL handle", __func__); | 
| 372 | 0 |                 return (FIDO_ERR_INVALID_ARGUMENT); | 
| 373 | 0 |         } | 
| 374 |  |  | 
| 375 | 114k |         if (io == NULL || io->open == NULL || io->close == NULL || | 
| 376 | 114k |             io->read == NULL || io->write == NULL) { | 
| 377 | 0 |                 fido_log_debug("%s: NULL function", __func__); | 
| 378 | 0 |                 return (FIDO_ERR_INVALID_ARGUMENT); | 
| 379 | 0 |         } | 
| 380 |  |  | 
| 381 | 114k |         dev->io = *io; | 
| 382 | 114k |         dev->io_own = true; | 
| 383 |  |  | 
| 384 | 114k |         return (FIDO_OK); | 
| 385 | 114k | } | 
| 386 |  |  | 
| 387 |  | int | 
| 388 |  | fido_dev_set_transport_functions(fido_dev_t *dev, const fido_dev_transport_t *t) | 
| 389 | 1.60k | { | 
| 390 | 1.60k |         if (dev->io_handle != NULL) { | 
| 391 | 0 |                 fido_log_debug("%s: non-NULL handle", __func__); | 
| 392 | 0 |                 return (FIDO_ERR_INVALID_ARGUMENT); | 
| 393 | 0 |         } | 
| 394 |  |  | 
| 395 | 1.60k |         dev->transport = *t; | 
| 396 | 1.60k |         dev->io_own = true; | 
| 397 |  |  | 
| 398 | 1.60k |         return (FIDO_OK); | 
| 399 | 1.60k | } | 
| 400 |  |  | 
| 401 |  | void * | 
| 402 |  | fido_dev_io_handle(const fido_dev_t *dev) | 
| 403 | 0 | { | 
| 404 |  | 
 | 
| 405 | 0 |         return (dev->io_handle); | 
| 406 | 0 | } | 
| 407 |  |  | 
| 408 |  | void | 
| 409 |  | fido_init(int flags) | 
| 410 | 30.1k | { | 
| 411 | 30.1k |         if (flags & FIDO_DEBUG || getenv("FIDO_DEBUG") != NULL) | 
| 412 | 30.1k |                 fido_log_init(); | 
| 413 |  |  | 
| 414 | 30.1k |         disable_u2f_fallback = (flags & FIDO_DISABLE_U2F_FALLBACK); | 
| 415 | 30.1k | } | 
| 416 |  |  | 
| 417 |  | fido_dev_t * | 
| 418 |  | fido_dev_new(void) | 
| 419 | 851k | { | 
| 420 | 851k |         fido_dev_t *dev; | 
| 421 |  |  | 
| 422 | 851k |         if ((dev = calloc(1, sizeof(*dev))) == NULL) | 
| 423 | 2.07k |                 return (NULL); | 
| 424 |  |  | 
| 425 | 849k |         dev->cid = CTAP_CID_BROADCAST; | 
| 426 | 849k |         dev->timeout_ms = -1; | 
| 427 | 849k |         dev->io = (fido_dev_io_t) { | 
| 428 | 849k |                 &fido_hid_open, | 
| 429 | 849k |                 &fido_hid_close, | 
| 430 | 849k |                 &fido_hid_read, | 
| 431 | 849k |                 &fido_hid_write, | 
| 432 | 849k |         }; | 
| 433 |  |  | 
| 434 | 849k |         return (dev); | 
| 435 | 851k | } | 
| 436 |  |  | 
| 437 |  | fido_dev_t * | 
| 438 |  | fido_dev_new_with_info(const fido_dev_info_t *di) | 
| 439 | 0 | { | 
| 440 | 0 |         fido_dev_t *dev; | 
| 441 |  | 
 | 
| 442 | 0 |         if ((dev = calloc(1, sizeof(*dev))) == NULL) | 
| 443 | 0 |                 return (NULL); | 
| 444 |  |  | 
| 445 |  | #if 0 | 
| 446 |  |         if (di->io.open == NULL || di->io.close == NULL || | 
| 447 |  |             di->io.read == NULL || di->io.write == NULL) { | 
| 448 |  |                 fido_log_debug("%s: NULL function", __func__); | 
| 449 |  |                 fido_dev_free(&dev); | 
| 450 |  |                 return (NULL); | 
| 451 |  |         } | 
| 452 |  | #endif | 
| 453 |  |  | 
| 454 | 0 |         dev->io = di->io; | 
| 455 | 0 |         dev->io_own = di->transport.tx != NULL || di->transport.rx != NULL; | 
| 456 | 0 |         dev->transport = di->transport; | 
| 457 | 0 |         dev->cid = CTAP_CID_BROADCAST; | 
| 458 | 0 |         dev->timeout_ms = -1; | 
| 459 |  | 
 | 
| 460 | 0 |         if ((dev->path = strdup(di->path)) == NULL) { | 
| 461 | 0 |                 fido_log_debug("%s: strdup", __func__); | 
| 462 | 0 |                 fido_dev_free(&dev); | 
| 463 | 0 |                 return (NULL); | 
| 464 | 0 |         } | 
| 465 |  |  | 
| 466 | 0 |         return (dev); | 
| 467 | 0 | } | 
| 468 |  |  | 
| 469 |  | void | 
| 470 |  | fido_dev_free(fido_dev_t **dev_p) | 
| 471 | 863k | { | 
| 472 | 863k |         fido_dev_t *dev; | 
| 473 |  |  | 
| 474 | 863k |         if (dev_p == NULL || (dev = *dev_p) == NULL) | 
| 475 | 14.0k |                 return; | 
| 476 |  |  | 
| 477 | 849k |         free(dev->path); | 
| 478 | 849k |         free(dev); | 
| 479 |  |  | 
| 480 | 849k |         *dev_p = NULL; | 
| 481 | 849k | } | 
| 482 |  |  | 
| 483 |  | uint8_t | 
| 484 |  | fido_dev_protocol(const fido_dev_t *dev) | 
| 485 | 316 | { | 
| 486 | 316 |         return (dev->attr.protocol); | 
| 487 | 316 | } | 
| 488 |  |  | 
| 489 |  | uint8_t | 
| 490 |  | fido_dev_major(const fido_dev_t *dev) | 
| 491 | 316 | { | 
| 492 | 316 |         return (dev->attr.major); | 
| 493 | 316 | } | 
| 494 |  |  | 
| 495 |  | uint8_t | 
| 496 |  | fido_dev_minor(const fido_dev_t *dev) | 
| 497 | 316 | { | 
| 498 | 316 |         return (dev->attr.minor); | 
| 499 | 316 | } | 
| 500 |  |  | 
| 501 |  | uint8_t | 
| 502 |  | fido_dev_build(const fido_dev_t *dev) | 
| 503 | 316 | { | 
| 504 | 316 |         return (dev->attr.build); | 
| 505 | 316 | } | 
| 506 |  |  | 
| 507 |  | uint8_t | 
| 508 |  | fido_dev_flags(const fido_dev_t *dev) | 
| 509 | 316 | { | 
| 510 | 316 |         return (dev->attr.flags); | 
| 511 | 316 | } | 
| 512 |  |  | 
| 513 |  | bool | 
| 514 |  | fido_dev_is_fido2(const fido_dev_t *dev) | 
| 515 | 137k | { | 
| 516 | 137k |         return (dev->attr.flags & FIDO_CAP_CBOR); | 
| 517 | 137k | } | 
| 518 |  |  | 
| 519 |  | bool | 
| 520 |  | fido_dev_is_winhello(const fido_dev_t *dev) | 
| 521 | 0 | { | 
| 522 | 0 |         return (dev->flags & FIDO_DEV_WINHELLO); | 
| 523 | 0 | } | 
| 524 |  |  | 
| 525 |  | bool | 
| 526 |  | fido_dev_supports_pin(const fido_dev_t *dev) | 
| 527 | 5.26k | { | 
| 528 | 5.26k |         return (dev->flags & (FIDO_DEV_PIN_SET|FIDO_DEV_PIN_UNSET)); | 
| 529 | 5.26k | } | 
| 530 |  |  | 
| 531 |  | bool | 
| 532 |  | fido_dev_has_pin(const fido_dev_t *dev) | 
| 533 | 5.01k | { | 
| 534 | 5.01k |         return (dev->flags & FIDO_DEV_PIN_SET); | 
| 535 | 5.01k | } | 
| 536 |  |  | 
| 537 |  | bool | 
| 538 |  | fido_dev_supports_cred_prot(const fido_dev_t *dev) | 
| 539 | 7.18k | { | 
| 540 | 7.18k |         return (dev->flags & FIDO_DEV_CRED_PROT); | 
| 541 | 7.18k | } | 
| 542 |  |  | 
| 543 |  | bool | 
| 544 |  | fido_dev_supports_credman(const fido_dev_t *dev) | 
| 545 | 7.18k | { | 
| 546 | 7.18k |         return (dev->flags & (FIDO_DEV_CREDMAN|FIDO_DEV_CREDMAN_PRE)); | 
| 547 | 7.18k | } | 
| 548 |  |  | 
| 549 |  | bool | 
| 550 |  | fido_dev_supports_uv(const fido_dev_t *dev) | 
| 551 | 5.01k | { | 
| 552 | 5.01k |         return (dev->flags & (FIDO_DEV_UV_SET|FIDO_DEV_UV_UNSET)); | 
| 553 | 5.01k | } | 
| 554 |  |  | 
| 555 |  | bool | 
| 556 |  | fido_dev_has_uv(const fido_dev_t *dev) | 
| 557 | 5.14k | { | 
| 558 | 5.14k |         return (dev->flags & FIDO_DEV_UV_SET); | 
| 559 | 5.14k | } | 
| 560 |  |  | 
| 561 |  | bool | 
| 562 |  | fido_dev_supports_permissions(const fido_dev_t *dev) | 
| 563 | 8.27k | { | 
| 564 | 8.27k |         return (dev->flags & FIDO_DEV_TOKEN_PERMS); | 
| 565 | 8.27k | } | 
| 566 |  |  | 
| 567 |  | void | 
| 568 |  | fido_dev_force_u2f(fido_dev_t *dev) | 
| 569 | 26.8k | { | 
| 570 | 26.8k |         dev->attr.flags &= (uint8_t)~FIDO_CAP_CBOR; | 
| 571 | 26.8k |         dev->flags = 0; | 
| 572 | 26.8k | } | 
| 573 |  |  | 
| 574 |  | void | 
| 575 |  | fido_dev_force_fido2(fido_dev_t *dev) | 
| 576 | 0 | { | 
| 577 | 0 |         dev->attr.flags |= FIDO_CAP_CBOR; | 
| 578 | 0 | } | 
| 579 |  |  | 
| 580 |  | uint8_t | 
| 581 |  | fido_dev_get_pin_protocol(const fido_dev_t *dev) | 
| 582 | 37.7k | { | 
| 583 | 37.7k |         if (dev->flags & FIDO_DEV_PIN_PROTOCOL2) | 
| 584 | 3.55k |                 return (CTAP_PIN_PROTOCOL2); | 
| 585 | 34.1k |         else if (dev->flags & FIDO_DEV_PIN_PROTOCOL1) | 
| 586 | 28.3k |                 return (CTAP_PIN_PROTOCOL1); | 
| 587 |  |  | 
| 588 | 5.81k |         return (0); | 
| 589 | 37.7k | } | 
| 590 |  |  | 
| 591 |  | uint64_t | 
| 592 |  | fido_dev_maxmsgsize(const fido_dev_t *dev) | 
| 593 | 5.44k | { | 
| 594 | 5.44k |         return (dev->maxmsgsize); | 
| 595 | 5.44k | } | 
| 596 |  |  | 
| 597 |  | int | 
| 598 |  | fido_dev_set_timeout(fido_dev_t *dev, int ms) | 
| 599 | 114k | { | 
| 600 | 114k |         if (ms < -1) | 
| 601 | 0 |                 return (FIDO_ERR_INVALID_ARGUMENT); | 
| 602 |  |  | 
| 603 | 114k |         dev->timeout_ms = ms; | 
| 604 |  |  | 
| 605 | 114k |         return (FIDO_OK); | 
| 606 | 114k | } |