summaryrefslogtreecommitdiff
path: root/src/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dev.c')
-rw-r--r--src/dev.c223
1 files changed, 199 insertions, 24 deletions
diff --git a/src/dev.c b/src/dev.c
index d0efac7..51b9935 100644
--- a/src/dev.c
+++ b/src/dev.c
@@ -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)
46static int
47obtain_nonce(uint64_t *nonce)
48{
49 arc4random_buf(nonce, sizeof(*nonce));
50 return (0);
51}
52#elif defined(HAVE_GETRANDOM)
53static int
54obtain_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)
43static int 61static int
44obtain_nonce(uint64_t *nonce) 62obtain_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
89typedef 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
94static TLS dev_manifest_func_node_t *manifest_funcs = NULL;
95
96static void
97find_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
67static int 109static int
68fido_dev_open_tx(fido_dev_t *dev, const char *path) 110fido_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)
102static int 144static int
103fido_dev_open_rx(fido_dev_t *dev, int ms) 145fido_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;
125fail: 189fail:
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
132static int 200static int
@@ -142,6 +210,79 @@ fido_dev_open_wait(fido_dev_t *dev, const char *path, int ms)
142} 210}
143 211
144int 212int
213fido_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
233void
234fido_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
249int
250fido_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
276int
277fido_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
285int
145fido_dev_open(fido_dev_t *dev, const char *path) 286fido_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)
162int 303int
163fido_dev_cancel(fido_dev_t *dev) 304fido_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
172fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) 313fido_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
331int
332fido_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)
200fido_dev_t * 351fido_dev_t *
201fido_dev_new(void) 352fido_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
370fido_dev_t *
371fido_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;