xref: /openbsd-src/lib/libfido2/src/dev.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
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 {
56 	if (getrandom(nonce, sizeof(*nonce), 0) < 0)
57 		return (-1);
58 	return (0);
59 }
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 {
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 
109 static int
110 fido_dev_open_tx(fido_dev_t *dev, const char *path)
111 {
112 	const uint8_t cmd = CTAP_CMD_INIT;
113 
114 	if (dev->io_handle != NULL) {
115 		fido_log_debug("%s: handle=%p", __func__, dev->io_handle);
116 		return (FIDO_ERR_INVALID_ARGUMENT);
117 	}
118 
119 	if (dev->io.open == NULL || dev->io.close == NULL) {
120 		fido_log_debug("%s: NULL open/close", __func__);
121 		return (FIDO_ERR_INVALID_ARGUMENT);
122 	}
123 
124 	if (obtain_nonce(&dev->nonce) < 0) {
125 		fido_log_debug("%s: obtain_nonce", __func__);
126 		return (FIDO_ERR_INTERNAL);
127 	}
128 
129 	if ((dev->io_handle = dev->io.open(path)) == NULL) {
130 		fido_log_debug("%s: dev->io.open", __func__);
131 		return (FIDO_ERR_INTERNAL);
132 	}
133 
134 	if (fido_tx(dev, cmd, &dev->nonce, sizeof(dev->nonce)) < 0) {
135 		fido_log_debug("%s: fido_tx", __func__);
136 		dev->io.close(dev->io_handle);
137 		dev->io_handle = NULL;
138 		return (FIDO_ERR_TX);
139 	}
140 
141 	return (FIDO_OK);
142 }
143 
144 static int
145 fido_dev_open_rx(fido_dev_t *dev, int ms)
146 {
147 	fido_cbor_info_t	*info = NULL;
148 	int			 reply_len;
149 	int			 r;
150 
151 	if ((reply_len = fido_rx(dev, CTAP_CMD_INIT, &dev->attr,
152 	    sizeof(dev->attr), ms)) < 0) {
153 		fido_log_debug("%s: fido_rx", __func__);
154 		r = FIDO_ERR_RX;
155 		goto fail;
156 	}
157 
158 #ifdef FIDO_FUZZ
159 	dev->attr.nonce = dev->nonce;
160 #endif
161 
162 	if ((size_t)reply_len != sizeof(dev->attr) ||
163 	    dev->attr.nonce != dev->nonce) {
164 		fido_log_debug("%s: invalid nonce", __func__);
165 		r = FIDO_ERR_RX;
166 		goto fail;
167 	}
168 
169 	dev->cid = dev->attr.cid;
170 
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;
189 fail:
190 	fido_cbor_info_free(&info);
191 
192 	if (r != FIDO_OK) {
193 		dev->io.close(dev->io_handle);
194 		dev->io_handle = NULL;
195 	}
196 
197 	return (r);
198 }
199 
200 static int
201 fido_dev_open_wait(fido_dev_t *dev, const char *path, int ms)
202 {
203 	int r;
204 
205 	if ((r = fido_dev_open_tx(dev, path)) != FIDO_OK ||
206 	    (r = fido_dev_open_rx(dev, ms)) != FIDO_OK)
207 		return (r);
208 
209 	return (FIDO_OK);
210 }
211 
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
286 fido_dev_open(fido_dev_t *dev, const char *path)
287 {
288 	return (fido_dev_open_wait(dev, path, -1));
289 }
290 
291 int
292 fido_dev_close(fido_dev_t *dev)
293 {
294 	if (dev->io_handle == NULL || dev->io.close == NULL)
295 		return (FIDO_ERR_INVALID_ARGUMENT);
296 
297 	dev->io.close(dev->io_handle);
298 	dev->io_handle = NULL;
299 
300 	return (FIDO_OK);
301 }
302 
303 int
304 fido_dev_cancel(fido_dev_t *dev)
305 {
306 	if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0) < 0)
307 		return (FIDO_ERR_TX);
308 
309 	return (FIDO_OK);
310 }
311 
312 int
313 fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io)
314 {
315 	if (dev->io_handle != NULL) {
316 		fido_log_debug("%s: NULL handle", __func__);
317 		return (FIDO_ERR_INVALID_ARGUMENT);
318 	}
319 
320 	if (io == NULL || io->open == NULL || io->close == NULL ||
321 	    io->read == NULL || io->write == NULL) {
322 		fido_log_debug("%s: NULL function", __func__);
323 		return (FIDO_ERR_INVALID_ARGUMENT);
324 	}
325 
326 	dev->io = *io;
327 
328 	return (FIDO_OK);
329 }
330 
331 void
332 fido_init(int flags)
333 {
334 	if (flags & FIDO_DEBUG || getenv("FIDO_DEBUG") != NULL)
335 		fido_log_init();
336 }
337 
338 fido_dev_t *
339 fido_dev_new(void)
340 {
341 	fido_dev_t *dev;
342 
343 	if ((dev = calloc(1, sizeof(*dev))) == NULL)
344 		return (NULL);
345 
346 	dev->cid = CTAP_CID_BROADCAST;
347 	dev->io = (fido_dev_io_t) {
348 		&fido_hid_open,
349 		&fido_hid_close,
350 		&fido_hid_read,
351 		&fido_hid_write,
352 		NULL,
353 		NULL,
354 	};
355 
356 	return (dev);
357 }
358 
359 fido_dev_t *
360 fido_dev_new_with_info(const fido_dev_info_t *di)
361 {
362 	fido_dev_t *dev;
363 
364 	if ((dev = calloc(1, sizeof(*dev))) == NULL)
365 		return (NULL);
366 
367 	dev->cid = CTAP_CID_BROADCAST;
368 
369 	if (di->io.open == NULL || di->io.close == NULL ||
370 	    di->io.read == NULL || di->io.write == NULL) {
371 		fido_log_debug("%s: NULL function", __func__);
372 		fido_dev_free(&dev);
373 		return (NULL);
374 	}
375 
376 	dev->io = di->io;
377 	if ((dev->path = strdup(di->path)) == NULL) {
378 		fido_log_debug("%s: strdup", __func__);
379 		fido_dev_free(&dev);
380 		return (NULL);
381 	}
382 
383 	return (dev);
384 }
385 
386 void
387 fido_dev_free(fido_dev_t **dev_p)
388 {
389 	fido_dev_t *dev;
390 
391 	if (dev_p == NULL || (dev = *dev_p) == NULL)
392 		return;
393 
394 	free(dev->path);
395 	free(dev);
396 
397 	*dev_p = NULL;
398 }
399 
400 uint8_t
401 fido_dev_protocol(const fido_dev_t *dev)
402 {
403 	return (dev->attr.protocol);
404 }
405 
406 uint8_t
407 fido_dev_major(const fido_dev_t *dev)
408 {
409 	return (dev->attr.major);
410 }
411 
412 uint8_t
413 fido_dev_minor(const fido_dev_t *dev)
414 {
415 	return (dev->attr.minor);
416 }
417 
418 uint8_t
419 fido_dev_build(const fido_dev_t *dev)
420 {
421 	return (dev->attr.build);
422 }
423 
424 uint8_t
425 fido_dev_flags(const fido_dev_t *dev)
426 {
427 	return (dev->attr.flags);
428 }
429 
430 bool
431 fido_dev_is_fido2(const fido_dev_t *dev)
432 {
433 	return (dev->attr.flags & FIDO_CAP_CBOR);
434 }
435 
436 void
437 fido_dev_force_u2f(fido_dev_t *dev)
438 {
439 	dev->attr.flags &= ~FIDO_CAP_CBOR;
440 }
441 
442 void
443 fido_dev_force_fido2(fido_dev_t *dev)
444 {
445 	dev->attr.flags |= FIDO_CAP_CBOR;
446 }
447