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