1 /* 2 * Copyright (c) 2019-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 #undef NDEBUG 9 10 #include <assert.h> 11 #include <string.h> 12 #include <time.h> 13 14 #define _FIDO_INTERNAL 15 16 #include <fido.h> 17 18 #include "../fuzz/wiredata_fido2.h" 19 20 #define REPORT_LEN (64 + 1) 21 22 static uint8_t ctap_nonce[8]; 23 static uint8_t *wiredata_ptr; 24 static size_t wiredata_len; 25 static int fake_dev_handle; 26 static int initialised; 27 static long interval_ms; 28 29 #if defined(_MSC_VER) 30 static int 31 nanosleep(const struct timespec *rqtp, struct timespec *rmtp) 32 { 33 if (rmtp != NULL) { 34 errno = EINVAL; 35 return (-1); 36 } 37 38 Sleep((DWORD)(rqtp->tv_sec * 1000) + (DWORD)(rqtp->tv_nsec / 1000000)); 39 40 return (0); 41 } 42 #endif 43 44 static void * 45 dummy_open(const char *path) 46 { 47 (void)path; 48 49 return (&fake_dev_handle); 50 } 51 52 static void 53 dummy_close(void *handle) 54 { 55 assert(handle == &fake_dev_handle); 56 } 57 58 static int 59 dummy_read(void *handle, unsigned char *ptr, size_t len, int ms) 60 { 61 struct timespec tv; 62 size_t n; 63 long d; 64 65 assert(handle == &fake_dev_handle); 66 assert(ptr != NULL); 67 assert(len == REPORT_LEN - 1); 68 69 if (wiredata_ptr == NULL) 70 return (-1); 71 72 if (!initialised) { 73 assert(wiredata_len >= REPORT_LEN - 1); 74 memcpy(&wiredata_ptr[7], &ctap_nonce, sizeof(ctap_nonce)); 75 initialised = 1; 76 } 77 78 if (ms >= 0 && ms < interval_ms) 79 d = ms; 80 else 81 d = interval_ms; 82 83 if (d) { 84 tv.tv_sec = d / 1000; 85 tv.tv_nsec = (d % 1000) * 1000000; 86 if (nanosleep(&tv, NULL) == -1) 87 err(1, "nanosleep"); 88 } 89 90 if (d != interval_ms) 91 return (-1); /* timeout */ 92 93 if (wiredata_len < len) 94 n = wiredata_len; 95 else 96 n = len; 97 98 memcpy(ptr, wiredata_ptr, n); 99 wiredata_ptr += n; 100 wiredata_len -= n; 101 102 return ((int)n); 103 } 104 105 static int 106 dummy_write(void *handle, const unsigned char *ptr, size_t len) 107 { 108 struct timespec tv; 109 110 assert(handle == &fake_dev_handle); 111 assert(ptr != NULL); 112 assert(len == REPORT_LEN); 113 114 if (!initialised) 115 memcpy(&ctap_nonce, &ptr[8], sizeof(ctap_nonce)); 116 117 if (interval_ms) { 118 tv.tv_sec = interval_ms / 1000; 119 tv.tv_nsec = (interval_ms % 1000) * 1000000; 120 if (nanosleep(&tv, NULL) == -1) 121 err(1, "nanosleep"); 122 } 123 124 return ((int)len); 125 } 126 127 static uint8_t * 128 wiredata_setup(const uint8_t *data, size_t len) 129 { 130 const uint8_t ctap_init_data[] = { WIREDATA_CTAP_INIT }; 131 132 assert(wiredata_ptr == NULL); 133 assert(SIZE_MAX - len > sizeof(ctap_init_data)); 134 assert((wiredata_ptr = malloc(sizeof(ctap_init_data) + len)) != NULL); 135 136 #if defined(_MSC_VER) 137 #pragma warning(push) 138 #pragma warning(disable:6386) 139 #endif 140 memcpy(wiredata_ptr, ctap_init_data, sizeof(ctap_init_data)); 141 #if defined(_MSC_VER) 142 #pragma warning(pop) 143 #endif 144 145 if (len) 146 memcpy(wiredata_ptr + sizeof(ctap_init_data), data, len); 147 148 wiredata_len = sizeof(ctap_init_data) + len; 149 150 return (wiredata_ptr); 151 } 152 153 static void 154 wiredata_clear(uint8_t **wiredata) 155 { 156 free(*wiredata); 157 *wiredata = NULL; 158 wiredata_ptr = NULL; 159 wiredata_len = 0; 160 initialised = 0; 161 } 162 163 /* gh#56 */ 164 static void 165 open_iff_ok(void) 166 { 167 fido_dev_t *dev = NULL; 168 fido_dev_io_t io; 169 170 memset(&io, 0, sizeof(io)); 171 172 io.open = dummy_open; 173 io.close = dummy_close; 174 io.read = dummy_read; 175 io.write = dummy_write; 176 177 assert((dev = fido_dev_new()) != NULL); 178 assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK); 179 assert(fido_dev_open(dev, "dummy") == FIDO_ERR_RX); 180 assert(fido_dev_close(dev) == FIDO_ERR_INVALID_ARGUMENT); 181 182 fido_dev_free(&dev); 183 } 184 185 static void 186 reopen(void) 187 { 188 const uint8_t cbor_info_data[] = { WIREDATA_CTAP_CBOR_INFO }; 189 uint8_t *wiredata; 190 fido_dev_t *dev = NULL; 191 fido_dev_io_t io; 192 193 memset(&io, 0, sizeof(io)); 194 195 io.open = dummy_open; 196 io.close = dummy_close; 197 io.read = dummy_read; 198 io.write = dummy_write; 199 200 wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data)); 201 assert((dev = fido_dev_new()) != NULL); 202 assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK); 203 assert(fido_dev_open(dev, "dummy") == FIDO_OK); 204 assert(fido_dev_close(dev) == FIDO_OK); 205 wiredata_clear(&wiredata); 206 207 wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data)); 208 assert(fido_dev_open(dev, "dummy") == FIDO_OK); 209 assert(fido_dev_close(dev) == FIDO_OK); 210 fido_dev_free(&dev); 211 wiredata_clear(&wiredata); 212 } 213 214 static void 215 double_open(void) 216 { 217 const uint8_t cbor_info_data[] = { WIREDATA_CTAP_CBOR_INFO }; 218 uint8_t *wiredata; 219 fido_dev_t *dev = NULL; 220 fido_dev_io_t io; 221 222 memset(&io, 0, sizeof(io)); 223 224 io.open = dummy_open; 225 io.close = dummy_close; 226 io.read = dummy_read; 227 io.write = dummy_write; 228 229 wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data)); 230 assert((dev = fido_dev_new()) != NULL); 231 assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK); 232 assert(fido_dev_open(dev, "dummy") == FIDO_OK); 233 assert(fido_dev_open(dev, "dummy") == FIDO_ERR_INVALID_ARGUMENT); 234 assert(fido_dev_close(dev) == FIDO_OK); 235 fido_dev_free(&dev); 236 wiredata_clear(&wiredata); 237 } 238 239 static void 240 double_close(void) 241 { 242 const uint8_t cbor_info_data[] = { WIREDATA_CTAP_CBOR_INFO }; 243 uint8_t *wiredata; 244 fido_dev_t *dev = NULL; 245 fido_dev_io_t io; 246 247 memset(&io, 0, sizeof(io)); 248 249 io.open = dummy_open; 250 io.close = dummy_close; 251 io.read = dummy_read; 252 io.write = dummy_write; 253 254 wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data)); 255 assert((dev = fido_dev_new()) != NULL); 256 assert(fido_dev_close(dev) == FIDO_ERR_INVALID_ARGUMENT); 257 assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK); 258 assert(fido_dev_close(dev) == FIDO_ERR_INVALID_ARGUMENT); 259 assert(fido_dev_open(dev, "dummy") == FIDO_OK); 260 assert(fido_dev_close(dev) == FIDO_OK); 261 assert(fido_dev_close(dev) == FIDO_ERR_INVALID_ARGUMENT); 262 fido_dev_free(&dev); 263 wiredata_clear(&wiredata); 264 } 265 266 static void 267 is_fido2(void) 268 { 269 const uint8_t cbor_info_data[] = { WIREDATA_CTAP_CBOR_INFO }; 270 uint8_t *wiredata; 271 fido_dev_t *dev = NULL; 272 fido_dev_io_t io; 273 274 memset(&io, 0, sizeof(io)); 275 276 io.open = dummy_open; 277 io.close = dummy_close; 278 io.read = dummy_read; 279 io.write = dummy_write; 280 281 wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data)); 282 assert((dev = fido_dev_new()) != NULL); 283 assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK); 284 assert(fido_dev_open(dev, "dummy") == FIDO_OK); 285 assert(fido_dev_is_fido2(dev) == true); 286 assert(fido_dev_supports_pin(dev) == true); 287 fido_dev_force_u2f(dev); 288 assert(fido_dev_is_fido2(dev) == false); 289 assert(fido_dev_supports_pin(dev) == false); 290 assert(fido_dev_close(dev) == FIDO_OK); 291 wiredata_clear(&wiredata); 292 293 wiredata = wiredata_setup(NULL, 0); 294 assert(fido_dev_open(dev, "dummy") == FIDO_OK); 295 assert(fido_dev_is_fido2(dev) == false); 296 assert(fido_dev_supports_pin(dev) == false); 297 fido_dev_force_fido2(dev); 298 assert(fido_dev_is_fido2(dev) == true); 299 assert(fido_dev_supports_pin(dev) == false); 300 assert(fido_dev_close(dev) == FIDO_OK); 301 fido_dev_free(&dev); 302 wiredata_clear(&wiredata); 303 } 304 305 static void 306 has_pin(void) 307 { 308 const uint8_t set_pin_data[] = { 309 WIREDATA_CTAP_CBOR_INFO, 310 WIREDATA_CTAP_CBOR_AUTHKEY, 311 WIREDATA_CTAP_CBOR_STATUS, 312 WIREDATA_CTAP_CBOR_STATUS 313 }; 314 uint8_t *wiredata; 315 fido_dev_t *dev = NULL; 316 fido_dev_io_t io; 317 318 memset(&io, 0, sizeof(io)); 319 320 io.open = dummy_open; 321 io.close = dummy_close; 322 io.read = dummy_read; 323 io.write = dummy_write; 324 325 wiredata = wiredata_setup(set_pin_data, sizeof(set_pin_data)); 326 assert((dev = fido_dev_new()) != NULL); 327 assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK); 328 assert(fido_dev_open(dev, "dummy") == FIDO_OK); 329 assert(fido_dev_has_pin(dev) == false); 330 assert(fido_dev_set_pin(dev, "top secret", NULL) == FIDO_OK); 331 assert(fido_dev_has_pin(dev) == true); 332 assert(fido_dev_reset(dev) == FIDO_OK); 333 assert(fido_dev_has_pin(dev) == false); 334 assert(fido_dev_close(dev) == FIDO_OK); 335 fido_dev_free(&dev); 336 wiredata_clear(&wiredata); 337 } 338 339 static void 340 timeout_rx(void) 341 { 342 const uint8_t timeout_rx_data[] = { 343 WIREDATA_CTAP_CBOR_INFO, 344 WIREDATA_CTAP_KEEPALIVE, 345 WIREDATA_CTAP_KEEPALIVE, 346 WIREDATA_CTAP_KEEPALIVE, 347 WIREDATA_CTAP_KEEPALIVE, 348 WIREDATA_CTAP_KEEPALIVE, 349 WIREDATA_CTAP_CBOR_STATUS 350 }; 351 uint8_t *wiredata; 352 fido_dev_t *dev = NULL; 353 fido_dev_io_t io; 354 355 memset(&io, 0, sizeof(io)); 356 357 io.open = dummy_open; 358 io.close = dummy_close; 359 io.read = dummy_read; 360 io.write = dummy_write; 361 362 wiredata = wiredata_setup(timeout_rx_data, sizeof(timeout_rx_data)); 363 assert((dev = fido_dev_new()) != NULL); 364 assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK); 365 assert(fido_dev_open(dev, "dummy") == FIDO_OK); 366 assert(fido_dev_set_timeout(dev, 3 * 1000) == FIDO_OK); 367 interval_ms = 1000; 368 assert(fido_dev_reset(dev) == FIDO_ERR_RX); 369 assert(fido_dev_close(dev) == FIDO_OK); 370 fido_dev_free(&dev); 371 wiredata_clear(&wiredata); 372 interval_ms = 0; 373 } 374 375 static void 376 timeout_ok(void) 377 { 378 const uint8_t timeout_ok_data[] = { 379 WIREDATA_CTAP_CBOR_INFO, 380 WIREDATA_CTAP_KEEPALIVE, 381 WIREDATA_CTAP_KEEPALIVE, 382 WIREDATA_CTAP_KEEPALIVE, 383 WIREDATA_CTAP_KEEPALIVE, 384 WIREDATA_CTAP_KEEPALIVE, 385 WIREDATA_CTAP_CBOR_STATUS 386 }; 387 uint8_t *wiredata; 388 fido_dev_t *dev = NULL; 389 fido_dev_io_t io; 390 391 memset(&io, 0, sizeof(io)); 392 393 io.open = dummy_open; 394 io.close = dummy_close; 395 io.read = dummy_read; 396 io.write = dummy_write; 397 398 wiredata = wiredata_setup(timeout_ok_data, sizeof(timeout_ok_data)); 399 assert((dev = fido_dev_new()) != NULL); 400 assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK); 401 assert(fido_dev_open(dev, "dummy") == FIDO_OK); 402 assert(fido_dev_set_timeout(dev, 30 * 1000) == FIDO_OK); 403 interval_ms = 1000; 404 assert(fido_dev_reset(dev) == FIDO_OK); 405 assert(fido_dev_close(dev) == FIDO_OK); 406 fido_dev_free(&dev); 407 wiredata_clear(&wiredata); 408 interval_ms = 0; 409 } 410 411 static void 412 timeout_misc(void) 413 { 414 fido_dev_t *dev; 415 416 assert((dev = fido_dev_new()) != NULL); 417 assert(fido_dev_set_timeout(dev, -2) == FIDO_ERR_INVALID_ARGUMENT); 418 assert(fido_dev_set_timeout(dev, 3 * 1000) == FIDO_OK); 419 assert(fido_dev_set_timeout(dev, -1) == FIDO_OK); 420 fido_dev_free(&dev); 421 } 422 423 int 424 main(void) 425 { 426 fido_init(0); 427 428 open_iff_ok(); 429 reopen(); 430 double_open(); 431 double_close(); 432 is_fido2(); 433 has_pin(); 434 timeout_rx(); 435 timeout_ok(); 436 timeout_misc(); 437 438 exit(0); 439 } 440