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 <sys/types.h> 8 #include <sys/stat.h> 9 #ifdef HAVE_SYS_RANDOM_H 10 #include <sys/random.h> 11 #endif 12 13 #include <fcntl.h> 14 #include <stdint.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #ifdef HAVE_UNISTD_H 18 #include <unistd.h> 19 #endif 20 21 #include "fido.h" 22 23 #if defined(_WIN32) 24 #include <windows.h> 25 26 #include <winternl.h> 27 #include <winerror.h> 28 #include <stdio.h> 29 #include <bcrypt.h> 30 #include <sal.h> 31 32 static int 33 obtain_nonce(uint64_t *nonce) 34 { 35 NTSTATUS status; 36 37 status = BCryptGenRandom(NULL, (unsigned char *)nonce, sizeof(*nonce), 38 BCRYPT_USE_SYSTEM_PREFERRED_RNG); 39 40 if (!NT_SUCCESS(status)) 41 return (-1); 42 43 return (0); 44 } 45 #elif defined(HAVE_ARC4RANDOM_BUF) 46 static int 47 obtain_nonce(uint64_t *nonce) 48 { 49 arc4random_buf(nonce, sizeof(*nonce)); 50 return (0); 51 } 52 #elif defined(HAVE_GETRANDOM) 53 static int 54 obtain_nonce(uint64_t *nonce) 55 { 56 if (getrandom(nonce, sizeof(*nonce), 0) < 0) 57 return (-1); 58 return (0); 59 } 60 #elif defined(HAVE_DEV_URANDOM) 61 static int 62 obtain_nonce(uint64_t *nonce) 63 { 64 int fd = -1; 65 int ok = -1; 66 ssize_t r; 67 68 if ((fd = open(FIDO_RANDOM_DEV, O_RDONLY)) < 0) 69 goto fail; 70 if ((r = read(fd, nonce, sizeof(*nonce))) < 0 || 71 (size_t)r != sizeof(*nonce)) 72 goto fail; 73 74 ok = 0; 75 fail: 76 if (fd != -1) 77 close(fd); 78 79 return (ok); 80 } 81 #else 82 #error "please provide an implementation of obtain_nonce() for your platform" 83 #endif /* _WIN32 */ 84 85 #ifndef TLS 86 #define TLS 87 #endif 88 89 typedef struct dev_manifest_func_node { 90 dev_manifest_func_t manifest_func; 91 struct dev_manifest_func_node *next; 92 } dev_manifest_func_node_t; 93 94 static TLS dev_manifest_func_node_t *manifest_funcs = NULL; 95 96 static void 97 find_manifest_func_node(dev_manifest_func_t f, dev_manifest_func_node_t **curr, 98 dev_manifest_func_node_t **prev) 99 { 100 *prev = NULL; 101 *curr = manifest_funcs; 102 103 while (*curr != NULL && (*curr)->manifest_func != f) { 104 *prev = *curr; 105 *curr = (*curr)->next; 106 } 107 } 108 109 static int 110 fido_dev_open_tx(fido_dev_t *dev, const char *path) 111 { 112 const uint8_t cmd = CTAP_CMD_INIT; 113 114 if (dev->io_handle != NULL) { 115 fido_log_debug("%s: handle=%p", __func__, dev->io_handle); 116 return (FIDO_ERR_INVALID_ARGUMENT); 117 } 118 119 if (dev->io.open == NULL || dev->io.close == NULL) { 120 fido_log_debug("%s: NULL open/close", __func__); 121 return (FIDO_ERR_INVALID_ARGUMENT); 122 } 123 124 if (obtain_nonce(&dev->nonce) < 0) { 125 fido_log_debug("%s: obtain_nonce", __func__); 126 return (FIDO_ERR_INTERNAL); 127 } 128 129 if ((dev->io_handle = dev->io.open(path)) == NULL) { 130 fido_log_debug("%s: dev->io.open", __func__); 131 return (FIDO_ERR_INTERNAL); 132 } 133 134 if (fido_tx(dev, cmd, &dev->nonce, sizeof(dev->nonce)) < 0) { 135 fido_log_debug("%s: fido_tx", __func__); 136 dev->io.close(dev->io_handle); 137 dev->io_handle = NULL; 138 return (FIDO_ERR_TX); 139 } 140 141 return (FIDO_OK); 142 } 143 144 static int 145 fido_dev_open_rx(fido_dev_t *dev, int ms) 146 { 147 fido_cbor_info_t *info = NULL; 148 int reply_len; 149 int r; 150 151 if ((reply_len = fido_rx(dev, CTAP_CMD_INIT, &dev->attr, 152 sizeof(dev->attr), ms)) < 0) { 153 fido_log_debug("%s: fido_rx", __func__); 154 r = FIDO_ERR_RX; 155 goto fail; 156 } 157 158 #ifdef FIDO_FUZZ 159 dev->attr.nonce = dev->nonce; 160 #endif 161 162 if ((size_t)reply_len != sizeof(dev->attr) || 163 dev->attr.nonce != dev->nonce) { 164 fido_log_debug("%s: invalid nonce", __func__); 165 r = FIDO_ERR_RX; 166 goto fail; 167 } 168 169 dev->cid = dev->attr.cid; 170 171 if (fido_dev_is_fido2(dev)) { 172 if ((info = fido_cbor_info_new()) == NULL) { 173 fido_log_debug("%s: fido_cbor_info_new", __func__); 174 r = FIDO_ERR_INTERNAL; 175 goto fail; 176 } 177 if (fido_dev_get_cbor_info_wait(dev, info, ms) != FIDO_OK) { 178 fido_log_debug("%s: falling back to u2f", __func__); 179 fido_dev_force_u2f(dev); 180 } 181 } 182 183 if (fido_dev_is_fido2(dev) && info != NULL) { 184 fido_log_debug("%s: FIDO_MAXMSG=%d, maxmsgsiz=%lu", __func__, 185 FIDO_MAXMSG, (unsigned long)fido_cbor_info_maxmsgsiz(info)); 186 } 187 188 r = FIDO_OK; 189 fail: 190 fido_cbor_info_free(&info); 191 192 if (r != FIDO_OK) { 193 dev->io.close(dev->io_handle); 194 dev->io_handle = NULL; 195 } 196 197 return (r); 198 } 199 200 static int 201 fido_dev_open_wait(fido_dev_t *dev, const char *path, int ms) 202 { 203 int r; 204 205 if ((r = fido_dev_open_tx(dev, path)) != FIDO_OK || 206 (r = fido_dev_open_rx(dev, ms)) != FIDO_OK) 207 return (r); 208 209 return (FIDO_OK); 210 } 211 212 int 213 fido_dev_register_manifest_func(const dev_manifest_func_t f) 214 { 215 dev_manifest_func_node_t *prev, *curr, *n; 216 217 find_manifest_func_node(f, &curr, &prev); 218 if (curr != NULL) 219 return (FIDO_OK); 220 221 if ((n = calloc(1, sizeof(*n))) == NULL) { 222 fido_log_debug("%s: calloc", __func__); 223 return (FIDO_ERR_INTERNAL); 224 } 225 226 n->manifest_func = f; 227 n->next = manifest_funcs; 228 manifest_funcs = n; 229 230 return (FIDO_OK); 231 } 232 233 void 234 fido_dev_unregister_manifest_func(const dev_manifest_func_t f) 235 { 236 dev_manifest_func_node_t *prev, *curr; 237 238 find_manifest_func_node(f, &curr, &prev); 239 if (curr == NULL) 240 return; 241 if (prev != NULL) 242 prev->next = curr->next; 243 else 244 manifest_funcs = curr->next; 245 246 free(curr); 247 } 248 249 int 250 fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) 251 { 252 dev_manifest_func_node_t *curr = NULL; 253 dev_manifest_func_t m_func; 254 size_t curr_olen; 255 int r; 256 257 *olen = 0; 258 259 if (fido_dev_register_manifest_func(fido_hid_manifest) != FIDO_OK) 260 return (FIDO_ERR_INTERNAL); 261 262 for (curr = manifest_funcs; curr != NULL; curr = curr->next) { 263 curr_olen = 0; 264 m_func = curr->manifest_func; 265 r = m_func(devlist + *olen, ilen - *olen, &curr_olen); 266 if (r != FIDO_OK) 267 return (r); 268 *olen += curr_olen; 269 if (*olen == ilen) 270 break; 271 } 272 273 return (FIDO_OK); 274 } 275 276 int 277 fido_dev_open_with_info(fido_dev_t *dev) 278 { 279 if (dev->path == NULL) 280 return (FIDO_ERR_INVALID_ARGUMENT); 281 282 return (fido_dev_open_wait(dev, dev->path, -1)); 283 } 284 285 int 286 fido_dev_open(fido_dev_t *dev, const char *path) 287 { 288 return (fido_dev_open_wait(dev, path, -1)); 289 } 290 291 int 292 fido_dev_close(fido_dev_t *dev) 293 { 294 if (dev->io_handle == NULL || dev->io.close == NULL) 295 return (FIDO_ERR_INVALID_ARGUMENT); 296 297 dev->io.close(dev->io_handle); 298 dev->io_handle = NULL; 299 300 return (FIDO_OK); 301 } 302 303 int 304 fido_dev_cancel(fido_dev_t *dev) 305 { 306 if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0) < 0) 307 return (FIDO_ERR_TX); 308 309 return (FIDO_OK); 310 } 311 312 int 313 fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) 314 { 315 if (dev->io_handle != NULL) { 316 fido_log_debug("%s: non-NULL handle", __func__); 317 return (FIDO_ERR_INVALID_ARGUMENT); 318 } 319 320 if (io == NULL || io->open == NULL || io->close == NULL || 321 io->read == NULL || io->write == NULL) { 322 fido_log_debug("%s: NULL function", __func__); 323 return (FIDO_ERR_INVALID_ARGUMENT); 324 } 325 326 dev->io = *io; 327 328 return (FIDO_OK); 329 } 330 331 int 332 fido_dev_set_transport_functions(fido_dev_t *dev, const fido_dev_transport_t *t) 333 { 334 if (dev->io_handle != NULL) { 335 fido_log_debug("%s: non-NULL handle", __func__); 336 return (FIDO_ERR_INVALID_ARGUMENT); 337 } 338 339 dev->transport = *t; 340 341 return (FIDO_OK); 342 } 343 344 void 345 fido_init(int flags) 346 { 347 if (flags & FIDO_DEBUG || getenv("FIDO_DEBUG") != NULL) 348 fido_log_init(); 349 } 350 351 fido_dev_t * 352 fido_dev_new(void) 353 { 354 fido_dev_t *dev; 355 356 if ((dev = calloc(1, sizeof(*dev))) == NULL) 357 return (NULL); 358 359 dev->cid = CTAP_CID_BROADCAST; 360 dev->io = (fido_dev_io_t) { 361 &fido_hid_open, 362 &fido_hid_close, 363 &fido_hid_read, 364 &fido_hid_write, 365 }; 366 367 return (dev); 368 } 369 370 fido_dev_t * 371 fido_dev_new_with_info(const fido_dev_info_t *di) 372 { 373 fido_dev_t *dev; 374 375 if ((dev = calloc(1, sizeof(*dev))) == NULL) 376 return (NULL); 377 378 dev->cid = CTAP_CID_BROADCAST; 379 380 if (di->io.open == NULL || di->io.close == NULL || 381 di->io.read == NULL || di->io.write == NULL) { 382 fido_log_debug("%s: NULL function", __func__); 383 fido_dev_free(&dev); 384 return (NULL); 385 } 386 387 dev->io = di->io; 388 dev->transport = di->transport; 389 390 if ((dev->path = strdup(di->path)) == NULL) { 391 fido_log_debug("%s: strdup", __func__); 392 fido_dev_free(&dev); 393 return (NULL); 394 } 395 396 return (dev); 397 } 398 399 void 400 fido_dev_free(fido_dev_t **dev_p) 401 { 402 fido_dev_t *dev; 403 404 if (dev_p == NULL || (dev = *dev_p) == NULL) 405 return; 406 407 free(dev->path); 408 free(dev); 409 410 *dev_p = NULL; 411 } 412 413 uint8_t 414 fido_dev_protocol(const fido_dev_t *dev) 415 { 416 return (dev->attr.protocol); 417 } 418 419 uint8_t 420 fido_dev_major(const fido_dev_t *dev) 421 { 422 return (dev->attr.major); 423 } 424 425 uint8_t 426 fido_dev_minor(const fido_dev_t *dev) 427 { 428 return (dev->attr.minor); 429 } 430 431 uint8_t 432 fido_dev_build(const fido_dev_t *dev) 433 { 434 return (dev->attr.build); 435 } 436 437 uint8_t 438 fido_dev_flags(const fido_dev_t *dev) 439 { 440 return (dev->attr.flags); 441 } 442 443 bool 444 fido_dev_is_fido2(const fido_dev_t *dev) 445 { 446 return (dev->attr.flags & FIDO_CAP_CBOR); 447 } 448 449 void 450 fido_dev_force_u2f(fido_dev_t *dev) 451 { 452 dev->attr.flags &= ~FIDO_CAP_CBOR; 453 } 454 455 void 456 fido_dev_force_fido2(fido_dev_t *dev) 457 { 458 dev->attr.flags |= FIDO_CAP_CBOR; 459 } 460