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 *
dummy_open(const char * path)22 dummy_open(const char *path)
23 {
24 (void)path;
25
26 return (FAKE_DEV_HANDLE);
27 }
28
29 static void
dummy_close(void * handle)30 dummy_close(void *handle)
31 {
32 assert(handle == FAKE_DEV_HANDLE);
33 }
34
35 static int
dummy_read(void * handle,unsigned char * ptr,size_t len,int ms)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
dummy_write(void * handle,const unsigned char * ptr,size_t len)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 *
wiredata_setup(const uint8_t * data,size_t len)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
wiredata_clear(uint8_t ** wiredata)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
open_iff_ok(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
reopen(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
double_open(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
is_fido2(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
has_pin(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
main(void)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