diff options
Diffstat (limited to 'src/dev.c')
-rw-r--r-- | src/dev.c | 223 |
1 files changed, 199 insertions, 24 deletions
@@ -6,6 +6,9 @@ | |||
6 | 6 | ||
7 | #include <sys/types.h> | 7 | #include <sys/types.h> |
8 | #include <sys/stat.h> | 8 | #include <sys/stat.h> |
9 | #ifdef HAVE_SYS_RANDOM_H | ||
10 | #include <sys/random.h> | ||
11 | #endif | ||
9 | 12 | ||
10 | #include <fcntl.h> | 13 | #include <fcntl.h> |
11 | #include <stdint.h> | 14 | #include <stdint.h> |
@@ -39,7 +42,22 @@ obtain_nonce(uint64_t *nonce) | |||
39 | 42 | ||
40 | return (0); | 43 | return (0); |
41 | } | 44 | } |
42 | #elif defined(HAS_DEV_URANDOM) | 45 | #elif defined(HAVE_ARC4RANDOM_BUF) |
46 | static int | ||
47 | obtain_nonce(uint64_t *nonce) | ||
48 | { | ||
49 | arc4random_buf(nonce, sizeof(*nonce)); | ||
50 | return (0); | ||
51 | } | ||
52 | #elif defined(HAVE_GETRANDOM) | ||
53 | static int | ||
54 | obtain_nonce(uint64_t *nonce) | ||
55 | { | ||
56 | if (getrandom(nonce, sizeof(*nonce), 0) < 0) | ||
57 | return (-1); | ||
58 | return (0); | ||
59 | } | ||
60 | #elif defined(HAVE_DEV_URANDOM) | ||
43 | static int | 61 | static int |
44 | obtain_nonce(uint64_t *nonce) | 62 | obtain_nonce(uint64_t *nonce) |
45 | { | 63 | { |
@@ -64,10 +82,34 @@ fail: | |||
64 | #error "please provide an implementation of obtain_nonce() for your platform" | 82 | #error "please provide an implementation of obtain_nonce() for your platform" |
65 | #endif /* _WIN32 */ | 83 | #endif /* _WIN32 */ |
66 | 84 | ||
85 | #ifndef TLS | ||
86 | #define TLS | ||
87 | #endif | ||
88 | |||
89 | typedef struct dev_manifest_func_node { | ||
90 | dev_manifest_func_t manifest_func; | ||
91 | struct dev_manifest_func_node *next; | ||
92 | } dev_manifest_func_node_t; | ||
93 | |||
94 | static TLS dev_manifest_func_node_t *manifest_funcs = NULL; | ||
95 | |||
96 | static void | ||
97 | find_manifest_func_node(dev_manifest_func_t f, dev_manifest_func_node_t **curr, | ||
98 | dev_manifest_func_node_t **prev) | ||
99 | { | ||
100 | *prev = NULL; | ||
101 | *curr = manifest_funcs; | ||
102 | |||
103 | while (*curr != NULL && (*curr)->manifest_func != f) { | ||
104 | *prev = *curr; | ||
105 | *curr = (*curr)->next; | ||
106 | } | ||
107 | } | ||
108 | |||
67 | static int | 109 | static int |
68 | fido_dev_open_tx(fido_dev_t *dev, const char *path) | 110 | fido_dev_open_tx(fido_dev_t *dev, const char *path) |
69 | { | 111 | { |
70 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_INIT; | 112 | const uint8_t cmd = CTAP_CMD_INIT; |
71 | 113 | ||
72 | if (dev->io_handle != NULL) { | 114 | if (dev->io_handle != NULL) { |
73 | fido_log_debug("%s: handle=%p", __func__, dev->io_handle); | 115 | fido_log_debug("%s: handle=%p", __func__, dev->io_handle); |
@@ -102,11 +144,14 @@ fido_dev_open_tx(fido_dev_t *dev, const char *path) | |||
102 | static int | 144 | static int |
103 | fido_dev_open_rx(fido_dev_t *dev, int ms) | 145 | fido_dev_open_rx(fido_dev_t *dev, int ms) |
104 | { | 146 | { |
105 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_INIT; | 147 | fido_cbor_info_t *info = NULL; |
106 | int n; | 148 | int reply_len; |
149 | int r; | ||
107 | 150 | ||
108 | if ((n = fido_rx(dev, cmd, &dev->attr, sizeof(dev->attr), ms)) < 0) { | 151 | if ((reply_len = fido_rx(dev, CTAP_CMD_INIT, &dev->attr, |
152 | sizeof(dev->attr), ms)) < 0) { | ||
109 | fido_log_debug("%s: fido_rx", __func__); | 153 | fido_log_debug("%s: fido_rx", __func__); |
154 | r = FIDO_ERR_RX; | ||
110 | goto fail; | 155 | goto fail; |
111 | } | 156 | } |
112 | 157 | ||
@@ -114,19 +159,42 @@ fido_dev_open_rx(fido_dev_t *dev, int ms) | |||
114 | dev->attr.nonce = dev->nonce; | 159 | dev->attr.nonce = dev->nonce; |
115 | #endif | 160 | #endif |
116 | 161 | ||
117 | if ((size_t)n != sizeof(dev->attr) || dev->attr.nonce != dev->nonce) { | 162 | if ((size_t)reply_len != sizeof(dev->attr) || |
163 | dev->attr.nonce != dev->nonce) { | ||
118 | fido_log_debug("%s: invalid nonce", __func__); | 164 | fido_log_debug("%s: invalid nonce", __func__); |
165 | r = FIDO_ERR_RX; | ||
119 | goto fail; | 166 | goto fail; |
120 | } | 167 | } |
121 | 168 | ||
122 | dev->cid = dev->attr.cid; | 169 | dev->cid = dev->attr.cid; |
123 | 170 | ||
124 | return (FIDO_OK); | 171 | if (fido_dev_is_fido2(dev)) { |
172 | if ((info = fido_cbor_info_new()) == NULL) { | ||
173 | fido_log_debug("%s: fido_cbor_info_new", __func__); | ||
174 | r = FIDO_ERR_INTERNAL; | ||
175 | goto fail; | ||
176 | } | ||
177 | if (fido_dev_get_cbor_info_wait(dev, info, ms) != FIDO_OK) { | ||
178 | fido_log_debug("%s: falling back to u2f", __func__); | ||
179 | fido_dev_force_u2f(dev); | ||
180 | } | ||
181 | } | ||
182 | |||
183 | if (fido_dev_is_fido2(dev) && info != NULL) { | ||
184 | fido_log_debug("%s: FIDO_MAXMSG=%d, maxmsgsiz=%lu", __func__, | ||
185 | FIDO_MAXMSG, (unsigned long)fido_cbor_info_maxmsgsiz(info)); | ||
186 | } | ||
187 | |||
188 | r = FIDO_OK; | ||
125 | fail: | 189 | fail: |
126 | dev->io.close(dev->io_handle); | 190 | fido_cbor_info_free(&info); |
127 | dev->io_handle = NULL; | 191 | |
192 | if (r != FIDO_OK) { | ||
193 | dev->io.close(dev->io_handle); | ||
194 | dev->io_handle = NULL; | ||
195 | } | ||
128 | 196 | ||
129 | return (FIDO_ERR_RX); | 197 | return (r); |
130 | } | 198 | } |
131 | 199 | ||
132 | static int | 200 | static int |
@@ -142,6 +210,79 @@ fido_dev_open_wait(fido_dev_t *dev, const char *path, int ms) | |||
142 | } | 210 | } |
143 | 211 | ||
144 | int | 212 | int |
213 | fido_dev_register_manifest_func(const dev_manifest_func_t f) | ||
214 | { | ||
215 | dev_manifest_func_node_t *prev, *curr, *n; | ||
216 | |||
217 | find_manifest_func_node(f, &curr, &prev); | ||
218 | if (curr != NULL) | ||
219 | return (FIDO_OK); | ||
220 | |||
221 | if ((n = calloc(1, sizeof(*n))) == NULL) { | ||
222 | fido_log_debug("%s: calloc", __func__); | ||
223 | return (FIDO_ERR_INTERNAL); | ||
224 | } | ||
225 | |||
226 | n->manifest_func = f; | ||
227 | n->next = manifest_funcs; | ||
228 | manifest_funcs = n; | ||
229 | |||
230 | return (FIDO_OK); | ||
231 | } | ||
232 | |||
233 | void | ||
234 | fido_dev_unregister_manifest_func(const dev_manifest_func_t f) | ||
235 | { | ||
236 | dev_manifest_func_node_t *prev, *curr; | ||
237 | |||
238 | find_manifest_func_node(f, &curr, &prev); | ||
239 | if (curr == NULL) | ||
240 | return; | ||
241 | if (prev != NULL) | ||
242 | prev->next = curr->next; | ||
243 | else | ||
244 | manifest_funcs = curr->next; | ||
245 | |||
246 | free(curr); | ||
247 | } | ||
248 | |||
249 | int | ||
250 | fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) | ||
251 | { | ||
252 | dev_manifest_func_node_t *curr = NULL; | ||
253 | dev_manifest_func_t m_func; | ||
254 | size_t curr_olen; | ||
255 | int r; | ||
256 | |||
257 | *olen = 0; | ||
258 | |||
259 | if (fido_dev_register_manifest_func(fido_hid_manifest) != FIDO_OK) | ||
260 | return (FIDO_ERR_INTERNAL); | ||
261 | |||
262 | for (curr = manifest_funcs; curr != NULL; curr = curr->next) { | ||
263 | curr_olen = 0; | ||
264 | m_func = curr->manifest_func; | ||
265 | r = m_func(devlist + *olen, ilen - *olen, &curr_olen); | ||
266 | if (r != FIDO_OK) | ||
267 | return (r); | ||
268 | *olen += curr_olen; | ||
269 | if (*olen == ilen) | ||
270 | break; | ||
271 | } | ||
272 | |||
273 | return (FIDO_OK); | ||
274 | } | ||
275 | |||
276 | int | ||
277 | fido_dev_open_with_info(fido_dev_t *dev) | ||
278 | { | ||
279 | if (dev->path == NULL) | ||
280 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
281 | |||
282 | return (fido_dev_open_wait(dev, dev->path, -1)); | ||
283 | } | ||
284 | |||
285 | int | ||
145 | fido_dev_open(fido_dev_t *dev, const char *path) | 286 | fido_dev_open(fido_dev_t *dev, const char *path) |
146 | { | 287 | { |
147 | return (fido_dev_open_wait(dev, path, -1)); | 288 | return (fido_dev_open_wait(dev, path, -1)); |
@@ -162,7 +303,7 @@ fido_dev_close(fido_dev_t *dev) | |||
162 | int | 303 | int |
163 | fido_dev_cancel(fido_dev_t *dev) | 304 | fido_dev_cancel(fido_dev_t *dev) |
164 | { | 305 | { |
165 | if (fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CANCEL, NULL, 0) < 0) | 306 | if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0) < 0) |
166 | return (FIDO_ERR_TX); | 307 | return (FIDO_ERR_TX); |
167 | 308 | ||
168 | return (FIDO_OK); | 309 | return (FIDO_OK); |
@@ -172,7 +313,7 @@ int | |||
172 | fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) | 313 | fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) |
173 | { | 314 | { |
174 | if (dev->io_handle != NULL) { | 315 | if (dev->io_handle != NULL) { |
175 | fido_log_debug("%s: NULL handle", __func__); | 316 | fido_log_debug("%s: non-NULL handle", __func__); |
176 | return (FIDO_ERR_INVALID_ARGUMENT); | 317 | return (FIDO_ERR_INVALID_ARGUMENT); |
177 | } | 318 | } |
178 | 319 | ||
@@ -182,10 +323,20 @@ fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) | |||
182 | return (FIDO_ERR_INVALID_ARGUMENT); | 323 | return (FIDO_ERR_INVALID_ARGUMENT); |
183 | } | 324 | } |
184 | 325 | ||
185 | dev->io.open = io->open; | 326 | dev->io = *io; |
186 | dev->io.close = io->close; | 327 | |
187 | dev->io.read = io->read; | 328 | return (FIDO_OK); |
188 | dev->io.write = io->write; | 329 | } |
330 | |||
331 | int | ||
332 | fido_dev_set_transport_functions(fido_dev_t *dev, const fido_dev_transport_t *t) | ||
333 | { | ||
334 | if (dev->io_handle != NULL) { | ||
335 | fido_log_debug("%s: non-NULL handle", __func__); | ||
336 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
337 | } | ||
338 | |||
339 | dev->transport = *t; | ||
189 | 340 | ||
190 | return (FIDO_OK); | 341 | return (FIDO_OK); |
191 | } | 342 | } |
@@ -200,21 +351,44 @@ fido_init(int flags) | |||
200 | fido_dev_t * | 351 | fido_dev_t * |
201 | fido_dev_new(void) | 352 | fido_dev_new(void) |
202 | { | 353 | { |
203 | fido_dev_t *dev; | 354 | fido_dev_t *dev; |
204 | fido_dev_io_t io; | ||
205 | 355 | ||
206 | if ((dev = calloc(1, sizeof(*dev))) == NULL) | 356 | if ((dev = calloc(1, sizeof(*dev))) == NULL) |
207 | return (NULL); | 357 | return (NULL); |
208 | 358 | ||
209 | dev->cid = CTAP_CID_BROADCAST; | 359 | dev->cid = CTAP_CID_BROADCAST; |
360 | dev->io = (fido_dev_io_t) { | ||
361 | &fido_hid_open, | ||
362 | &fido_hid_close, | ||
363 | &fido_hid_read, | ||
364 | &fido_hid_write, | ||
365 | }; | ||
366 | |||
367 | return (dev); | ||
368 | } | ||
369 | |||
370 | fido_dev_t * | ||
371 | fido_dev_new_with_info(const fido_dev_info_t *di) | ||
372 | { | ||
373 | fido_dev_t *dev; | ||
374 | |||
375 | if ((dev = calloc(1, sizeof(*dev))) == NULL) | ||
376 | return (NULL); | ||
377 | |||
378 | dev->cid = CTAP_CID_BROADCAST; | ||
379 | |||
380 | if (di->io.open == NULL || di->io.close == NULL || | ||
381 | di->io.read == NULL || di->io.write == NULL) { | ||
382 | fido_log_debug("%s: NULL function", __func__); | ||
383 | fido_dev_free(&dev); | ||
384 | return (NULL); | ||
385 | } | ||
210 | 386 | ||
211 | io.open = fido_hid_open; | 387 | dev->io = di->io; |
212 | io.close = fido_hid_close; | 388 | dev->transport = di->transport; |
213 | io.read = fido_hid_read; | ||
214 | io.write = fido_hid_write; | ||
215 | 389 | ||
216 | if (fido_dev_set_io_functions(dev, &io) != FIDO_OK) { | 390 | if ((dev->path = strdup(di->path)) == NULL) { |
217 | fido_log_debug("%s: fido_dev_set_io_functions", __func__); | 391 | fido_log_debug("%s: strdup", __func__); |
218 | fido_dev_free(&dev); | 392 | fido_dev_free(&dev); |
219 | return (NULL); | 393 | return (NULL); |
220 | } | 394 | } |
@@ -230,6 +404,7 @@ fido_dev_free(fido_dev_t **dev_p) | |||
230 | if (dev_p == NULL || (dev = *dev_p) == NULL) | 404 | if (dev_p == NULL || (dev = *dev_p) == NULL) |
231 | return; | 405 | return; |
232 | 406 | ||
407 | free(dev->path); | ||
233 | free(dev); | 408 | free(dev); |
234 | 409 | ||
235 | *dev_p = NULL; | 410 | *dev_p = NULL; |