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 22static uint8_t ctap_nonce[8]; 23static uint8_t *wiredata_ptr; 24static size_t wiredata_len; 25static int fake_dev_handle; 26static int initialised; 27static long interval_ms; 28 29#if defined(_MSC_VER) 30static int 31nanosleep(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 44static void * 45dummy_open(const char *path) 46{ 47 (void)path; 48 49 return (&fake_dev_handle); 50} 51 52static void 53dummy_close(void *handle) 54{ 55 assert(handle == &fake_dev_handle); 56} 57 58static int 59dummy_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 105static int 106dummy_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 127static uint8_t * 128wiredata_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 153static void 154wiredata_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 */ 164static void 165open_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 185static void 186reopen(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 214static void 215double_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 239static void 240double_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 266static void 267is_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 305static void 306has_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 339static void 340timeout_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 375static void 376timeout_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 411static void 412timeout_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 423int 424main(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