diff options
author | nicoo <nicoo@debian.org> | 2020-02-12 13:42:22 +0100 |
---|---|---|
committer | Nicolas Braud-Santoni <nicolas@braud-santoni.eu> | 2020-02-12 13:42:22 +0100 |
commit | c79050aa44b8836d836c5dd22a383a073c28b74b (patch) | |
tree | 7bcca9fabd7718bf87ca600a6594f57b76d8de7d /src/dev.c |
Import upstream release 1.3.0
Closes: #951184
Diffstat (limited to 'src/dev.c')
-rw-r--r-- | src/dev.c | 284 |
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 | |||
29 | static int | ||
30 | obtain_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) | ||
43 | static int | ||
44 | obtain_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; | ||
57 | fail: | ||
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 | |||
67 | static int | ||
68 | fido_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 | |||
102 | static int | ||
103 | fido_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); | ||
125 | fail: | ||
126 | dev->io.close(dev->io_handle); | ||
127 | dev->io_handle = NULL; | ||
128 | |||
129 | return (FIDO_ERR_RX); | ||
130 | } | ||
131 | |||
132 | static int | ||
133 | fido_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 | |||
144 | int | ||
145 | fido_dev_open(fido_dev_t *dev, const char *path) | ||
146 | { | ||
147 | return (fido_dev_open_wait(dev, path, -1)); | ||
148 | } | ||
149 | |||
150 | int | ||
151 | fido_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 | |||
162 | int | ||
163 | fido_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 | |||
171 | int | ||
172 | fido_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 | |||
193 | void | ||
194 | fido_init(int flags) | ||
195 | { | ||
196 | if (flags & FIDO_DEBUG || getenv("FIDO_DEBUG") != NULL) | ||
197 | fido_log_init(); | ||
198 | } | ||
199 | |||
200 | fido_dev_t * | ||
201 | fido_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 | |||
225 | void | ||
226 | fido_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 | |||
238 | uint8_t | ||
239 | fido_dev_protocol(const fido_dev_t *dev) | ||
240 | { | ||
241 | return (dev->attr.protocol); | ||
242 | } | ||
243 | |||
244 | uint8_t | ||
245 | fido_dev_major(const fido_dev_t *dev) | ||
246 | { | ||
247 | return (dev->attr.major); | ||
248 | } | ||
249 | |||
250 | uint8_t | ||
251 | fido_dev_minor(const fido_dev_t *dev) | ||
252 | { | ||
253 | return (dev->attr.minor); | ||
254 | } | ||
255 | |||
256 | uint8_t | ||
257 | fido_dev_build(const fido_dev_t *dev) | ||
258 | { | ||
259 | return (dev->attr.build); | ||
260 | } | ||
261 | |||
262 | uint8_t | ||
263 | fido_dev_flags(const fido_dev_t *dev) | ||
264 | { | ||
265 | return (dev->attr.flags); | ||
266 | } | ||
267 | |||
268 | bool | ||
269 | fido_dev_is_fido2(const fido_dev_t *dev) | ||
270 | { | ||
271 | return (dev->attr.flags & FIDO_CAP_CBOR); | ||
272 | } | ||
273 | |||
274 | void | ||
275 | fido_dev_force_u2f(fido_dev_t *dev) | ||
276 | { | ||
277 | dev->attr.flags &= ~FIDO_CAP_CBOR; | ||
278 | } | ||
279 | |||
280 | void | ||
281 | fido_dev_force_fido2(fido_dev_t *dev) | ||
282 | { | ||
283 | dev->attr.flags |= FIDO_CAP_CBOR; | ||
284 | } | ||