Coverage Report

Created: 2020-03-07 10:10

/libfido2/src/dev.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2018 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 <sys/types.h>
8
#include <sys/stat.h>
9
#ifdef HAVE_SYS_RANDOM_H
10
#include <sys/random.h>
11
#endif
12
13
#include <fcntl.h>
14
#include <stdint.h>
15
#include <stdlib.h>
16
#include <string.h>
17
#ifdef HAVE_UNISTD_H
18
#include <unistd.h>
19
#endif
20
21
#include "fido.h"
22
23
#if defined(_WIN32)
24
#include <windows.h>
25
26
#include <winternl.h>
27
#include <winerror.h>
28
#include <stdio.h>
29
#include <bcrypt.h>
30
#include <sal.h>
31
32
static int
33
obtain_nonce(uint64_t *nonce)
34
{
35
        NTSTATUS status;
36
37
        status = BCryptGenRandom(NULL, (unsigned char *)nonce, sizeof(*nonce),
38
            BCRYPT_USE_SYSTEM_PREFERRED_RNG);
39
40
        if (!NT_SUCCESS(status))
41
                return (-1);
42
43
        return (0);
44
}
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
65.8k
{
56
65.8k
        if (getrandom(nonce, sizeof(*nonce), 0) < 0)
57
0
                return (-1);
58
65.8k
        return (0);
59
65.8k
}
60
#elif defined(HAVE_DEV_URANDOM)
61
static int
62
obtain_nonce(uint64_t *nonce)
63
{
64
        int     fd = -1;
65
        int     ok = -1;
66
        ssize_t r;
67
68
        if ((fd = open(FIDO_RANDOM_DEV, O_RDONLY)) < 0)
69
                goto fail;
70
        if ((r = read(fd, nonce, sizeof(*nonce))) < 0 ||
71
            (size_t)r != sizeof(*nonce))
72
                goto fail;
73
74
        ok = 0;
75
fail:
76
        if (fd != -1)
77
                close(fd);
78
79
        return (ok);
80
}
81
#else
82
#error "please provide an implementation of obtain_nonce() for your platform"
83
#endif /* _WIN32 */
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
0
{
100
0
        *prev = NULL;
101
0
        *curr = manifest_funcs;
102
0
103
0
        while (*curr != NULL && (*curr)->manifest_func != f) {
104
0
                *prev = *curr;
105
0
                *curr = (*curr)->next;
106
0
        }
107
0
}
108
109
static int
110
fido_dev_open_tx(fido_dev_t *dev, const char *path)
111
65.8k
{
112
65.8k
        const uint8_t cmd = CTAP_CMD_INIT;
113
65.8k
114
65.8k
        if (dev->io_handle != NULL) {
115
0
                fido_log_debug("%s: handle=%p", __func__, dev->io_handle);
116
0
                return (FIDO_ERR_INVALID_ARGUMENT);
117
0
        }
118
65.8k
119
65.8k
        if (dev->io.open == NULL || dev->io.close == NULL) {
120
0
                fido_log_debug("%s: NULL open/close", __func__);
121
0
                return (FIDO_ERR_INVALID_ARGUMENT);
122
0
        }
123
65.8k
124
65.8k
        if (obtain_nonce(&dev->nonce) < 0) {
125
0
                fido_log_debug("%s: obtain_nonce", __func__);
126
0
                return (FIDO_ERR_INTERNAL);
127
0
        }
128
65.8k
129
65.8k
        if ((dev->io_handle = dev->io.open(path)) == NULL) {
130
0
                fido_log_debug("%s: dev->io.open", __func__);
131
0
                return (FIDO_ERR_INTERNAL);
132
0
        }
133
65.8k
134
65.8k
        if (fido_tx(dev, cmd, &dev->nonce, sizeof(dev->nonce)) < 0) {
135
267
                fido_log_debug("%s: fido_tx", __func__);
136
267
                dev->io.close(dev->io_handle);
137
267
                dev->io_handle = NULL;
138
267
                return (FIDO_ERR_TX);
139
267
        }
140
65.5k
141
65.5k
        return (FIDO_OK);
142
65.5k
}
143
144
static int
145
fido_dev_open_rx(fido_dev_t *dev, int ms)
146
65.5k
{
147
65.5k
        fido_cbor_info_t        *info = NULL;
148
65.5k
        int                      reply_len;
149
65.5k
        int                      r;
150
65.5k
151
65.5k
        if ((reply_len = fido_rx(dev, CTAP_CMD_INIT, &dev->attr,
152
65.5k
            sizeof(dev->attr), ms)) < 0) {
153
37.6k
                fido_log_debug("%s: fido_rx", __func__);
154
37.6k
                r = FIDO_ERR_RX;
155
37.6k
                goto fail;
156
37.6k
        }
157
27.9k
158
27.9k
#ifdef FIDO_FUZZ
159
27.9k
        dev->attr.nonce = dev->nonce;
160
27.9k
#endif
161
27.9k
162
27.9k
        if ((size_t)reply_len != sizeof(dev->attr) ||
163
27.9k
            dev->attr.nonce != dev->nonce) {
164
668
                fido_log_debug("%s: invalid nonce", __func__);
165
668
                r = FIDO_ERR_RX;
166
668
                goto fail;
167
668
        }
168
27.2k
169
27.2k
        dev->cid = dev->attr.cid;
170
27.2k
171
27.2k
        if (fido_dev_is_fido2(dev)) {
172
18.4k
                if ((info = fido_cbor_info_new()) == NULL) {
173
29
                        fido_log_debug("%s: fido_cbor_info_new", __func__);
174
29
                        r = FIDO_ERR_INTERNAL;
175
29
                        goto fail;
176
29
                }
177
18.3k
                if (fido_dev_get_cbor_info_wait(dev, info, ms) != FIDO_OK) {
178
12.1k
                        fido_log_debug("%s: falling back to u2f", __func__);
179
12.1k
                        fido_dev_force_u2f(dev);
180
12.1k
                }
181
18.3k
        }
182
27.2k
183
27.2k
        if (fido_dev_is_fido2(dev) && info != NULL) {
184
6.26k
                fido_log_debug("%s: FIDO_MAXMSG=%d, maxmsgsiz=%lu", __func__,
185
6.26k
                    FIDO_MAXMSG, (unsigned long)fido_cbor_info_maxmsgsiz(info));
186
6.26k
        }
187
27.2k
188
27.2k
        r = FIDO_OK;
189
65.5k
fail:
190
65.5k
        fido_cbor_info_free(&info);
191
65.5k
192
65.5k
        if (r != FIDO_OK) {
193
38.3k
                dev->io.close(dev->io_handle);
194
38.3k
                dev->io_handle = NULL;
195
38.3k
        }
196
65.5k
197
65.5k
        return (r);
198
27.2k
}
199
200
static int
201
fido_dev_open_wait(fido_dev_t *dev, const char *path, int ms)
202
65.8k
{
203
65.8k
        int r;
204
65.8k
205
65.8k
        if ((r = fido_dev_open_tx(dev, path)) != FIDO_OK ||
206
65.8k
            (r = fido_dev_open_rx(dev, ms)) != FIDO_OK)
207
65.8k
                return (r);
208
27.2k
209
27.2k
        return (FIDO_OK);
210
27.2k
}
211
212
int
213
fido_dev_register_manifest_func(const dev_manifest_func_t f)
214
0
{
215
0
        dev_manifest_func_node_t *prev, *curr, *n;
216
0
217
0
        find_manifest_func_node(f, &curr, &prev);
218
0
        if (curr != NULL)
219
0
                return (FIDO_OK);
220
0
221
0
        if ((n = calloc(1, sizeof(*n))) == NULL) {
222
0
                fido_log_debug("%s: calloc", __func__);
223
0
                return (FIDO_ERR_INTERNAL);
224
0
        }
225
0
226
0
        n->manifest_func = f;
227
0
        n->next = manifest_funcs;
228
0
        manifest_funcs = n;
229
0
230
0
        return (FIDO_OK);
231
0
}
232
233
void
234
fido_dev_unregister_manifest_func(const dev_manifest_func_t f)
235
0
{
236
0
        dev_manifest_func_node_t *prev, *curr;
237
0
238
0
        find_manifest_func_node(f, &curr, &prev);
239
0
        if (curr == NULL)
240
0
                return;
241
0
        if (prev != NULL)
242
0
                prev->next = curr->next;
243
0
        else
244
0
                manifest_funcs = curr->next;
245
0
246
0
        free(curr);
247
0
}
248
249
int
250
fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
251
0
{
252
0
        dev_manifest_func_node_t        *curr = NULL;
253
0
        dev_manifest_func_t              m_func;
254
0
        size_t                           curr_olen;
255
0
        int                              r;
256
0
257
0
        *olen = 0;
258
0
259
0
        if (fido_dev_register_manifest_func(fido_hid_manifest) != FIDO_OK)
260
0
                return (FIDO_ERR_INTERNAL);
261
0
262
0
        for (curr = manifest_funcs; curr != NULL; curr = curr->next) {
263
0
                curr_olen = 0;
264
0
                m_func = curr->manifest_func;
265
0
                r = m_func(devlist + *olen, ilen - *olen, &curr_olen);
266
0
                if (r != FIDO_OK)
267
0
                        return (r);
268
0
                *olen += curr_olen;
269
0
                if (*olen == ilen)
270
0
                        break;
271
0
        }
272
0
273
0
        return (FIDO_OK);
274
0
}
275
276
int
277
fido_dev_open_with_info(fido_dev_t *dev)
278
0
{
279
0
        if (dev->path == NULL)
280
0
                return (FIDO_ERR_INVALID_ARGUMENT);
281
0
282
0
        return (fido_dev_open_wait(dev, dev->path, -1));
283
0
}
284
285
int
286
fido_dev_open(fido_dev_t *dev, const char *path)
287
65.8k
{
288
65.8k
        return (fido_dev_open_wait(dev, path, -1));
289
65.8k
}
290
291
int
292
fido_dev_close(fido_dev_t *dev)
293
27.2k
{
294
27.2k
        if (dev->io_handle == NULL || dev->io.close == NULL)
295
27.2k
                return (FIDO_ERR_INVALID_ARGUMENT);
296
27.2k
297
27.2k
        dev->io.close(dev->io_handle);
298
27.2k
        dev->io_handle = NULL;
299
27.2k
300
27.2k
        return (FIDO_OK);
301
27.2k
}
302
303
int
304
fido_dev_cancel(fido_dev_t *dev)
305
7.12k
{
306
7.12k
        if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0) < 0)
307
30
                return (FIDO_ERR_TX);
308
7.09k
309
7.09k
        return (FIDO_OK);
310
7.09k
}
311
312
int
313
fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io)
314
65.8k
{
315
65.8k
        if (dev->io_handle != NULL) {
316
0
                fido_log_debug("%s: non-NULL handle", __func__);
317
0
                return (FIDO_ERR_INVALID_ARGUMENT);
318
0
        }
319
65.8k
320
65.8k
        if (io == NULL || io->open == NULL || io->close == NULL ||
321
65.8k
            io->read == NULL || io->write == NULL) {
322
0
                fido_log_debug("%s: NULL function", __func__);
323
0
                return (FIDO_ERR_INVALID_ARGUMENT);
324
0
        }
325
65.8k
326
65.8k
        dev->io = *io;
327
65.8k
328
65.8k
        return (FIDO_OK);
329
65.8k
}
330
331
int
332
fido_dev_set_transport_functions(fido_dev_t *dev, const fido_dev_transport_t *t)
333
0
{
334
0
        if (dev->io_handle != NULL) {
335
0
                fido_log_debug("%s: non-NULL handle", __func__);
336
0
                return (FIDO_ERR_INVALID_ARGUMENT);
337
0
        }
338
0
339
0
        dev->transport = *t;
340
0
341
0
        return (FIDO_OK);
342
0
}
343
344
void
345
fido_init(int flags)
346
19.9k
{
347
19.9k
        if (flags & FIDO_DEBUG || getenv("FIDO_DEBUG") != NULL)
348
19.9k
                fido_log_init();
349
19.9k
}
350
351
fido_dev_t *
352
fido_dev_new(void)
353
65.9k
{
354
65.9k
        fido_dev_t *dev;
355
65.9k
356
65.9k
        if ((dev = calloc(1, sizeof(*dev))) == NULL)
357
65.9k
                return (NULL);
358
65.8k
359
65.8k
        dev->cid = CTAP_CID_BROADCAST;
360
65.8k
        dev->io = (fido_dev_io_t) {
361
65.8k
                &fido_hid_open,
362
65.8k
                &fido_hid_close,
363
65.8k
                &fido_hid_read,
364
65.8k
                &fido_hid_write,
365
65.8k
        };
366
65.8k
367
65.8k
        return (dev);
368
65.8k
}
369
370
fido_dev_t *
371
fido_dev_new_with_info(const fido_dev_info_t *di)
372
0
{
373
0
        fido_dev_t *dev;
374
0
375
0
        if ((dev = calloc(1, sizeof(*dev))) == NULL)
376
0
                return (NULL);
377
0
378
0
        dev->cid = CTAP_CID_BROADCAST;
379
0
380
0
        if (di->io.open == NULL || di->io.close == NULL ||
381
0
            di->io.read == NULL || di->io.write == NULL) {
382
0
                fido_log_debug("%s: NULL function", __func__);
383
0
                fido_dev_free(&dev);
384
0
                return (NULL);
385
0
        }
386
0
387
0
        dev->io = di->io;
388
0
        dev->transport = di->transport;
389
0
390
0
        if ((dev->path = strdup(di->path)) == NULL) {
391
0
                fido_log_debug("%s: strdup", __func__);
392
0
                fido_dev_free(&dev);
393
0
                return (NULL);
394
0
        }
395
0
396
0
        return (dev);
397
0
}
398
399
void
400
fido_dev_free(fido_dev_t **dev_p)
401
81.5k
{
402
81.5k
        fido_dev_t *dev;
403
81.5k
404
81.5k
        if (dev_p == NULL || (dev = *dev_p) == NULL)
405
81.5k
                return;
406
65.8k
407
65.8k
        free(dev->path);
408
65.8k
        free(dev);
409
65.8k
410
65.8k
        *dev_p = NULL;
411
65.8k
}
412
413
uint8_t
414
fido_dev_protocol(const fido_dev_t *dev)
415
962
{
416
962
        return (dev->attr.protocol);
417
962
}
418
419
uint8_t
420
fido_dev_major(const fido_dev_t *dev)
421
962
{
422
962
        return (dev->attr.major);
423
962
}
424
425
uint8_t
426
fido_dev_minor(const fido_dev_t *dev)
427
962
{
428
962
        return (dev->attr.minor);
429
962
}
430
431
uint8_t
432
fido_dev_build(const fido_dev_t *dev)
433
962
{
434
962
        return (dev->attr.build);
435
962
}
436
437
uint8_t
438
fido_dev_flags(const fido_dev_t *dev)
439
962
{
440
962
        return (dev->attr.flags);
441
962
}
442
443
bool
444
fido_dev_is_fido2(const fido_dev_t *dev)
445
68.8k
{
446
68.8k
        return (dev->attr.flags & FIDO_CAP_CBOR);
447
68.8k
}
448
449
void
450
fido_dev_force_u2f(fido_dev_t *dev)
451
14.2k
{
452
14.2k
        dev->attr.flags &= ~FIDO_CAP_CBOR;
453
14.2k
}
454
455
void
456
fido_dev_force_fido2(fido_dev_t *dev)
457
0
{
458
0
        dev->attr.flags |= FIDO_CAP_CBOR;
459
0
}