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