xref: /freebsd/contrib/libfido2/regress/dev.c (revision 7259ca31048e5ced8e7f90657a3d7084aeafdf51)
1 /*
2  * Copyright (c) 2019 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 <fido.h>
9 #include <string.h>
10 
11 #include "../fuzz/wiredata_fido2.h"
12 
13 #define FAKE_DEV_HANDLE	((void *)0xdeadbeef)
14 #define REPORT_LEN	(64 + 1)
15 
16 static uint8_t	 ctap_nonce[8];
17 static uint8_t	*wiredata_ptr;
18 static size_t	 wiredata_len;
19 static int	 initialised;
20 
21 static void *
22 dummy_open(const char *path)
23 {
24 	(void)path;
25 
26 	return (FAKE_DEV_HANDLE);
27 }
28 
29 static void
30 dummy_close(void *handle)
31 {
32 	assert(handle == FAKE_DEV_HANDLE);
33 }
34 
35 static int
36 dummy_read(void *handle, unsigned char *ptr, size_t len, int ms)
37 {
38 	size_t n;
39 
40 	(void)ms;
41 
42 	assert(handle == FAKE_DEV_HANDLE);
43 	assert(ptr != NULL);
44 	assert(len == REPORT_LEN - 1);
45 
46 	if (wiredata_ptr == NULL)
47 		return (-1);
48 
49 	if (!initialised) {
50 		assert(wiredata_len >= REPORT_LEN - 1);
51 		memcpy(&wiredata_ptr[7], &ctap_nonce, sizeof(ctap_nonce));
52 		initialised = 1;
53 	}
54 
55 	if (wiredata_len < len)
56 		n = wiredata_len;
57 	else
58 		n = len;
59 
60 	memcpy(ptr, wiredata_ptr, n);
61 	wiredata_ptr += n;
62 	wiredata_len -= n;
63 
64 	return ((int)n);
65 }
66 
67 static int
68 dummy_write(void *handle, const unsigned char *ptr, size_t len)
69 {
70 	assert(handle == FAKE_DEV_HANDLE);
71 	assert(ptr != NULL);
72 	assert(len == REPORT_LEN);
73 
74 	if (!initialised)
75 		memcpy(&ctap_nonce, &ptr[8], sizeof(ctap_nonce));
76 
77 	return ((int)len);
78 }
79 
80 static uint8_t *
81 wiredata_setup(const uint8_t *data, size_t len)
82 {
83 	const uint8_t ctap_init_data[] = { WIREDATA_CTAP_INIT };
84 
85 	assert(wiredata_ptr == NULL);
86 	assert(SIZE_MAX - len > sizeof(ctap_init_data));
87 	assert((wiredata_ptr = malloc(sizeof(ctap_init_data) + len)) != NULL);
88 
89 	memcpy(wiredata_ptr, ctap_init_data, sizeof(ctap_init_data));
90 
91 	if (len)
92 		memcpy(wiredata_ptr + sizeof(ctap_init_data), data, len);
93 
94 	wiredata_len = sizeof(ctap_init_data) + len;
95 
96 	return (wiredata_ptr);
97 }
98 
99 static void
100 wiredata_clear(uint8_t **wiredata)
101 {
102 	free(*wiredata);
103 	*wiredata = NULL;
104 	wiredata_ptr = NULL;
105 	wiredata_len = 0;
106 	initialised = 0;
107 }
108 
109 /* gh#56 */
110 static void
111 open_iff_ok(void)
112 {
113 	fido_dev_t	*dev = NULL;
114 	fido_dev_io_t	 io;
115 
116 	memset(&io, 0, sizeof(io));
117 
118 	io.open = dummy_open;
119 	io.close = dummy_close;
120 	io.read = dummy_read;
121 	io.write = dummy_write;
122 
123 	assert((dev = fido_dev_new()) != NULL);
124 	assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK);
125 	assert(fido_dev_open(dev, "dummy") == FIDO_ERR_RX);
126 	assert(fido_dev_close(dev) == FIDO_ERR_INVALID_ARGUMENT);
127 
128 	fido_dev_free(&dev);
129 }
130 
131 static void
132 reopen(void)
133 {
134 	const uint8_t	 cbor_info_data[] = { WIREDATA_CTAP_CBOR_INFO };
135 	uint8_t		*wiredata;
136 	fido_dev_t	*dev = NULL;
137 	fido_dev_io_t	 io;
138 
139 	memset(&io, 0, sizeof(io));
140 
141 	io.open = dummy_open;
142 	io.close = dummy_close;
143 	io.read = dummy_read;
144 	io.write = dummy_write;
145 
146 	wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data));
147 	assert((dev = fido_dev_new()) != NULL);
148 	assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK);
149 	assert(fido_dev_open(dev, "dummy") == FIDO_OK);
150 	assert(fido_dev_close(dev) == FIDO_OK);
151 	wiredata_clear(&wiredata);
152 
153 	wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data));
154 	assert(fido_dev_open(dev, "dummy") == FIDO_OK);
155 	assert(fido_dev_close(dev) == FIDO_OK);
156 	wiredata_clear(&wiredata);
157 }
158 
159 static void
160 double_open(void)
161 {
162 	const uint8_t	 cbor_info_data[] = { WIREDATA_CTAP_CBOR_INFO };
163 	uint8_t		*wiredata;
164 	fido_dev_t	*dev = NULL;
165 	fido_dev_io_t	 io;
166 
167 	memset(&io, 0, sizeof(io));
168 
169 	io.open = dummy_open;
170 	io.close = dummy_close;
171 	io.read = dummy_read;
172 	io.write = dummy_write;
173 
174 	wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data));
175 	assert((dev = fido_dev_new()) != NULL);
176 	assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK);
177 	assert(fido_dev_open(dev, "dummy") == FIDO_OK);
178 	assert(fido_dev_open(dev, "dummy") == FIDO_ERR_INVALID_ARGUMENT);
179 	assert(fido_dev_close(dev) == FIDO_OK);
180 	wiredata_clear(&wiredata);
181 }
182 
183 static void
184 is_fido2(void)
185 {
186 	const uint8_t	 cbor_info_data[] = { WIREDATA_CTAP_CBOR_INFO };
187 	uint8_t		*wiredata;
188 	fido_dev_t	*dev = NULL;
189 	fido_dev_io_t	 io;
190 
191 	memset(&io, 0, sizeof(io));
192 
193 	io.open = dummy_open;
194 	io.close = dummy_close;
195 	io.read = dummy_read;
196 	io.write = dummy_write;
197 
198 	wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data));
199 	assert((dev = fido_dev_new()) != NULL);
200 	assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK);
201 	assert(fido_dev_open(dev, "dummy") == FIDO_OK);
202 	assert(fido_dev_is_fido2(dev) == true);
203 	assert(fido_dev_supports_pin(dev) == true);
204 	fido_dev_force_u2f(dev);
205 	assert(fido_dev_is_fido2(dev) == false);
206 	assert(fido_dev_supports_pin(dev) == false);
207 	assert(fido_dev_close(dev) == FIDO_OK);
208 	wiredata_clear(&wiredata);
209 
210 	wiredata = wiredata_setup(NULL, 0);
211 	assert(fido_dev_open(dev, "dummy") == FIDO_OK);
212 	assert(fido_dev_is_fido2(dev) == false);
213 	assert(fido_dev_supports_pin(dev) == false);
214 	fido_dev_force_fido2(dev);
215 	assert(fido_dev_is_fido2(dev) == true);
216 	assert(fido_dev_supports_pin(dev) == false);
217 	assert(fido_dev_close(dev) == FIDO_OK);
218 	wiredata_clear(&wiredata);
219 }
220 
221 static void
222 has_pin(void)
223 {
224 	const uint8_t	 set_pin_data[] = {
225 			    WIREDATA_CTAP_CBOR_INFO,
226 			    WIREDATA_CTAP_CBOR_AUTHKEY,
227 			    WIREDATA_CTAP_CBOR_STATUS,
228 			    WIREDATA_CTAP_CBOR_STATUS
229 			 };
230 	uint8_t		*wiredata;
231 	fido_dev_t	*dev = NULL;
232 	fido_dev_io_t	 io;
233 
234 	memset(&io, 0, sizeof(io));
235 
236 	io.open = dummy_open;
237 	io.close = dummy_close;
238 	io.read = dummy_read;
239 	io.write = dummy_write;
240 
241 	wiredata = wiredata_setup(set_pin_data, sizeof(set_pin_data));
242 	assert((dev = fido_dev_new()) != NULL);
243 	assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK);
244 	assert(fido_dev_open(dev, "dummy") == FIDO_OK);
245 	assert(fido_dev_has_pin(dev) == false);
246 	assert(fido_dev_set_pin(dev, "top secret", NULL) == FIDO_OK);
247 	assert(fido_dev_has_pin(dev) == true);
248 	assert(fido_dev_reset(dev) == FIDO_OK);
249 	assert(fido_dev_has_pin(dev) == false);
250 	assert(fido_dev_close(dev) == FIDO_OK);
251 	wiredata_clear(&wiredata);
252 }
253 
254 int
255 main(void)
256 {
257 	fido_init(0);
258 
259 	open_iff_ok();
260 	reopen();
261 	double_open();
262 	is_fido2();
263 	has_pin();
264 
265 	exit(0);
266 }
267