xref: /freebsd/contrib/libfido2/regress/dev.c (revision 6bfca4dcab07dad45a805879d954876b353c0810)
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