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
nanosleep(const struct timespec * rqtp,struct timespec * rmtp)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 *
dummy_open(const char * path)45 dummy_open(const char *path)
46 {
47 (void)path;
48
49 return (&fake_dev_handle);
50 }
51
52 static void
dummy_close(void * handle)53 dummy_close(void *handle)
54 {
55 assert(handle == &fake_dev_handle);
56 }
57
58 static int
dummy_read(void * handle,unsigned char * ptr,size_t len,int ms)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
dummy_write(void * handle,const unsigned char * ptr,size_t len)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 *
wiredata_setup(const uint8_t * data,size_t len)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
wiredata_clear(uint8_t ** wiredata)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
open_iff_ok(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
reopen(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
double_open(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
double_close(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
is_fido2(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
has_pin(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
timeout_rx(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
timeout_ok(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
timeout_misc(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
main(void)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