summaryrefslogtreecommitdiff
path: root/src/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dev.c')
-rw-r--r--src/dev.c284
1 files changed, 284 insertions, 0 deletions
diff --git a/src/dev.c b/src/dev.c
new file mode 100644
index 0000000..d0efac7
--- /dev/null
+++ b/src/dev.c
@@ -0,0 +1,284 @@
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
10#include <fcntl.h>
11#include <stdint.h>
12#include <stdlib.h>
13#include <string.h>
14#ifdef HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17
18#include "fido.h"
19
20#if defined(_WIN32)
21#include <windows.h>
22
23#include <winternl.h>
24#include <winerror.h>
25#include <stdio.h>
26#include <bcrypt.h>
27#include <sal.h>
28
29static int
30obtain_nonce(uint64_t *nonce)
31{
32 NTSTATUS status;
33
34 status = BCryptGenRandom(NULL, (unsigned char *)nonce, sizeof(*nonce),
35 BCRYPT_USE_SYSTEM_PREFERRED_RNG);
36
37 if (!NT_SUCCESS(status))
38 return (-1);
39
40 return (0);
41}
42#elif defined(HAS_DEV_URANDOM)
43static int
44obtain_nonce(uint64_t *nonce)
45{
46 int fd = -1;
47 int ok = -1;
48 ssize_t r;
49
50 if ((fd = open(FIDO_RANDOM_DEV, O_RDONLY)) < 0)
51 goto fail;
52 if ((r = read(fd, nonce, sizeof(*nonce))) < 0 ||
53 (size_t)r != sizeof(*nonce))
54 goto fail;
55
56 ok = 0;
57fail:
58 if (fd != -1)
59 close(fd);
60
61 return (ok);
62}
63#else
64#error "please provide an implementation of obtain_nonce() for your platform"
65#endif /* _WIN32 */
66
67static int
68fido_dev_open_tx(fido_dev_t *dev, const char *path)
69{
70 const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_INIT;
71
72 if (dev->io_handle != NULL) {
73 fido_log_debug("%s: handle=%p", __func__, dev->io_handle);
74 return (FIDO_ERR_INVALID_ARGUMENT);
75 }
76
77 if (dev->io.open == NULL || dev->io.close == NULL) {
78 fido_log_debug("%s: NULL open/close", __func__);
79 return (FIDO_ERR_INVALID_ARGUMENT);
80 }
81
82 if (obtain_nonce(&dev->nonce) < 0) {
83 fido_log_debug("%s: obtain_nonce", __func__);
84 return (FIDO_ERR_INTERNAL);
85 }
86
87 if ((dev->io_handle = dev->io.open(path)) == NULL) {
88 fido_log_debug("%s: dev->io.open", __func__);
89 return (FIDO_ERR_INTERNAL);
90 }
91
92 if (fido_tx(dev, cmd, &dev->nonce, sizeof(dev->nonce)) < 0) {
93 fido_log_debug("%s: fido_tx", __func__);
94 dev->io.close(dev->io_handle);
95 dev->io_handle = NULL;
96 return (FIDO_ERR_TX);
97 }
98
99 return (FIDO_OK);
100}
101
102static int
103fido_dev_open_rx(fido_dev_t *dev, int ms)
104{
105 const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_INIT;
106 int n;
107
108 if ((n = fido_rx(dev, cmd, &dev->attr, sizeof(dev->attr), ms)) < 0) {
109 fido_log_debug("%s: fido_rx", __func__);
110 goto fail;
111 }
112
113#ifdef FIDO_FUZZ
114 dev->attr.nonce = dev->nonce;
115#endif
116
117 if ((size_t)n != sizeof(dev->attr) || dev->attr.nonce != dev->nonce) {
118 fido_log_debug("%s: invalid nonce", __func__);
119 goto fail;
120 }
121
122 dev->cid = dev->attr.cid;
123
124 return (FIDO_OK);
125fail:
126 dev->io.close(dev->io_handle);
127 dev->io_handle = NULL;
128
129 return (FIDO_ERR_RX);
130}
131
132static int
133fido_dev_open_wait(fido_dev_t *dev, const char *path, int ms)
134{
135 int r;
136
137 if ((r = fido_dev_open_tx(dev, path)) != FIDO_OK ||
138 (r = fido_dev_open_rx(dev, ms)) != FIDO_OK)
139 return (r);
140
141 return (FIDO_OK);
142}
143
144int
145fido_dev_open(fido_dev_t *dev, const char *path)
146{
147 return (fido_dev_open_wait(dev, path, -1));
148}
149
150int
151fido_dev_close(fido_dev_t *dev)
152{
153 if (dev->io_handle == NULL || dev->io.close == NULL)
154 return (FIDO_ERR_INVALID_ARGUMENT);
155
156 dev->io.close(dev->io_handle);
157 dev->io_handle = NULL;
158
159 return (FIDO_OK);
160}
161
162int
163fido_dev_cancel(fido_dev_t *dev)
164{
165 if (fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CANCEL, NULL, 0) < 0)
166 return (FIDO_ERR_TX);
167
168 return (FIDO_OK);
169}
170
171int
172fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io)
173{
174 if (dev->io_handle != NULL) {
175 fido_log_debug("%s: NULL handle", __func__);
176 return (FIDO_ERR_INVALID_ARGUMENT);
177 }
178
179 if (io == NULL || io->open == NULL || io->close == NULL ||
180 io->read == NULL || io->write == NULL) {
181 fido_log_debug("%s: NULL function", __func__);
182 return (FIDO_ERR_INVALID_ARGUMENT);
183 }
184
185 dev->io.open = io->open;
186 dev->io.close = io->close;
187 dev->io.read = io->read;
188 dev->io.write = io->write;
189
190 return (FIDO_OK);
191}
192
193void
194fido_init(int flags)
195{
196 if (flags & FIDO_DEBUG || getenv("FIDO_DEBUG") != NULL)
197 fido_log_init();
198}
199
200fido_dev_t *
201fido_dev_new(void)
202{
203 fido_dev_t *dev;
204 fido_dev_io_t io;
205
206 if ((dev = calloc(1, sizeof(*dev))) == NULL)
207 return (NULL);
208
209 dev->cid = CTAP_CID_BROADCAST;
210
211 io.open = fido_hid_open;
212 io.close = fido_hid_close;
213 io.read = fido_hid_read;
214 io.write = fido_hid_write;
215
216 if (fido_dev_set_io_functions(dev, &io) != FIDO_OK) {
217 fido_log_debug("%s: fido_dev_set_io_functions", __func__);
218 fido_dev_free(&dev);
219 return (NULL);
220 }
221
222 return (dev);
223}
224
225void
226fido_dev_free(fido_dev_t **dev_p)
227{
228 fido_dev_t *dev;
229
230 if (dev_p == NULL || (dev = *dev_p) == NULL)
231 return;
232
233 free(dev);
234
235 *dev_p = NULL;
236}
237
238uint8_t
239fido_dev_protocol(const fido_dev_t *dev)
240{
241 return (dev->attr.protocol);
242}
243
244uint8_t
245fido_dev_major(const fido_dev_t *dev)
246{
247 return (dev->attr.major);
248}
249
250uint8_t
251fido_dev_minor(const fido_dev_t *dev)
252{
253 return (dev->attr.minor);
254}
255
256uint8_t
257fido_dev_build(const fido_dev_t *dev)
258{
259 return (dev->attr.build);
260}
261
262uint8_t
263fido_dev_flags(const fido_dev_t *dev)
264{
265 return (dev->attr.flags);
266}
267
268bool
269fido_dev_is_fido2(const fido_dev_t *dev)
270{
271 return (dev->attr.flags & FIDO_CAP_CBOR);
272}
273
274void
275fido_dev_force_u2f(fido_dev_t *dev)
276{
277 dev->attr.flags &= ~FIDO_CAP_CBOR;
278}
279
280void
281fido_dev_force_fido2(fido_dev_t *dev)
282{
283 dev->attr.flags |= FIDO_CAP_CBOR;
284}