xref: /openbsd-src/lib/libfido2/src/dev.c (revision fcde59b201a29a2b4570b00b71e7aa25d61cb5c1)
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 <openssl/sha.h>
14 
15 #include <fcntl.h>
16 #include <stdint.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22 
23 #include "fido.h"
24 
25 #if defined(_WIN32)
26 #include <windows.h>
27 
28 #include <winternl.h>
29 #include <winerror.h>
30 #include <stdio.h>
31 #include <bcrypt.h>
32 #include <sal.h>
33 
34 static int
35 obtain_nonce(uint64_t *nonce)
36 {
37 	NTSTATUS status;
38 
39 	status = BCryptGenRandom(NULL, (unsigned char *)nonce, sizeof(*nonce),
40 	    BCRYPT_USE_SYSTEM_PREFERRED_RNG);
41 
42 	if (!NT_SUCCESS(status))
43 		return (-1);
44 
45 	return (0);
46 }
47 #elif defined(HAVE_ARC4RANDOM_BUF)
48 static int
49 obtain_nonce(uint64_t *nonce)
50 {
51 	arc4random_buf(nonce, sizeof(*nonce));
52 	return (0);
53 }
54 #elif defined(HAVE_GETRANDOM)
55 static int
56 obtain_nonce(uint64_t *nonce)
57 {
58 	if (getrandom(nonce, sizeof(*nonce), 0) < 0)
59 		return (-1);
60 	return (0);
61 }
62 #elif defined(HAVE_DEV_URANDOM)
63 static int
64 obtain_nonce(uint64_t *nonce)
65 {
66 	int	fd = -1;
67 	int	ok = -1;
68 	ssize_t	r;
69 
70 	if ((fd = open(FIDO_RANDOM_DEV, O_RDONLY)) < 0)
71 		goto fail;
72 	if ((r = read(fd, nonce, sizeof(*nonce))) < 0 ||
73 	    (size_t)r != sizeof(*nonce))
74 		goto fail;
75 
76 	ok = 0;
77 fail:
78 	if (fd != -1)
79 		close(fd);
80 
81 	return (ok);
82 }
83 #else
84 #error "please provide an implementation of obtain_nonce() for your platform"
85 #endif /* _WIN32 */
86 
87 #ifndef TLS
88 #define TLS
89 #endif
90 
91 typedef struct dev_manifest_func_node {
92 	dev_manifest_func_t manifest_func;
93 	struct dev_manifest_func_node *next;
94 } dev_manifest_func_node_t;
95 
96 static TLS dev_manifest_func_node_t *manifest_funcs = NULL;
97 
98 static void
99 find_manifest_func_node(dev_manifest_func_t f, dev_manifest_func_node_t **curr,
100     dev_manifest_func_node_t **prev)
101 {
102 	*prev = NULL;
103 	*curr = manifest_funcs;
104 
105 	while (*curr != NULL && (*curr)->manifest_func != f) {
106 		*prev = *curr;
107 		*curr = (*curr)->next;
108 	}
109 }
110 
111 #ifdef FIDO_FUZZ
112 static void
113 set_random_report_len(fido_dev_t *dev)
114 {
115 	dev->rx_len = CTAP_MIN_REPORT_LEN +
116 	    uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1);
117 	dev->tx_len = CTAP_MIN_REPORT_LEN +
118 	    uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1);
119 }
120 #endif
121 
122 static void
123 fido_dev_set_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
124 {
125 	char * const	*ptr;
126 	const bool	*val;
127 	size_t		 len;
128 
129 	ptr = fido_cbor_info_extensions_ptr(info);
130 	len = fido_cbor_info_extensions_len(info);
131 
132 	for (size_t i = 0; i < len; i++)
133 		if (strcmp(ptr[i], "credProtect") == 0)
134 			dev->flags |= FIDO_DEV_CRED_PROT;
135 
136 	ptr = fido_cbor_info_options_name_ptr(info);
137 	val = fido_cbor_info_options_value_ptr(info);
138 	len = fido_cbor_info_options_len(info);
139 
140 	for (size_t i = 0; i < len; i++)
141 		if (strcmp(ptr[i], "clientPin") == 0) {
142 			if (val[i] == true)
143 				dev->flags |= FIDO_DEV_PIN_SET;
144 			else
145 				dev->flags |= FIDO_DEV_PIN_UNSET;
146 		}
147 }
148 
149 static int
150 fido_dev_open_tx(fido_dev_t *dev, const char *path)
151 {
152 	const uint8_t	cmd = CTAP_CMD_INIT;
153 	int		r;
154 
155 	if (dev->io_handle != NULL) {
156 		fido_log_debug("%s: handle=%p", __func__, dev->io_handle);
157 		return (FIDO_ERR_INVALID_ARGUMENT);
158 	}
159 
160 	if (dev->io.open == NULL || dev->io.close == NULL) {
161 		fido_log_debug("%s: NULL open/close", __func__);
162 		return (FIDO_ERR_INVALID_ARGUMENT);
163 	}
164 
165 	if (obtain_nonce(&dev->nonce) < 0) {
166 		fido_log_debug("%s: obtain_nonce", __func__);
167 		return (FIDO_ERR_INTERNAL);
168 	}
169 
170 	if ((dev->io_handle = dev->io.open(path)) == NULL) {
171 		fido_log_debug("%s: dev->io.open", __func__);
172 		return (FIDO_ERR_INTERNAL);
173 	}
174 
175 	if (dev->io_own) {
176 		dev->rx_len = CTAP_MAX_REPORT_LEN;
177 		dev->tx_len = CTAP_MAX_REPORT_LEN;
178 	} else {
179 		dev->rx_len = fido_hid_report_in_len(dev->io_handle);
180 		dev->tx_len = fido_hid_report_out_len(dev->io_handle);
181 	}
182 
183 #ifdef FIDO_FUZZ
184 	set_random_report_len(dev);
185 #endif
186 
187 	if (dev->rx_len < CTAP_MIN_REPORT_LEN ||
188 	    dev->rx_len > CTAP_MAX_REPORT_LEN) {
189 		fido_log_debug("%s: invalid rx_len %zu", __func__, dev->rx_len);
190 		r = FIDO_ERR_RX;
191 		goto fail;
192 	}
193 
194 	if (dev->tx_len < CTAP_MIN_REPORT_LEN ||
195 	    dev->tx_len > CTAP_MAX_REPORT_LEN) {
196 		fido_log_debug("%s: invalid tx_len %zu", __func__, dev->tx_len);
197 		r = FIDO_ERR_TX;
198 		goto fail;
199 	}
200 
201 	if (fido_tx(dev, cmd, &dev->nonce, sizeof(dev->nonce)) < 0) {
202 		fido_log_debug("%s: fido_tx", __func__);
203 		r = FIDO_ERR_TX;
204 		goto fail;
205 	}
206 
207 	return (FIDO_OK);
208 fail:
209 	dev->io.close(dev->io_handle);
210 	dev->io_handle = NULL;
211 
212 	return (r);
213 }
214 
215 static int
216 fido_dev_open_rx(fido_dev_t *dev, int ms)
217 {
218 	fido_cbor_info_t	*info = NULL;
219 	int			 reply_len;
220 	int			 r;
221 
222 	if ((reply_len = fido_rx(dev, CTAP_CMD_INIT, &dev->attr,
223 	    sizeof(dev->attr), ms)) < 0) {
224 		fido_log_debug("%s: fido_rx", __func__);
225 		r = FIDO_ERR_RX;
226 		goto fail;
227 	}
228 
229 #ifdef FIDO_FUZZ
230 	dev->attr.nonce = dev->nonce;
231 #endif
232 
233 	if ((size_t)reply_len != sizeof(dev->attr) ||
234 	    dev->attr.nonce != dev->nonce) {
235 		fido_log_debug("%s: invalid nonce", __func__);
236 		r = FIDO_ERR_RX;
237 		goto fail;
238 	}
239 
240 	dev->flags = 0;
241 	dev->cid = dev->attr.cid;
242 
243 	if (fido_dev_is_fido2(dev)) {
244 		if ((info = fido_cbor_info_new()) == NULL) {
245 			fido_log_debug("%s: fido_cbor_info_new", __func__);
246 			r = FIDO_ERR_INTERNAL;
247 			goto fail;
248 		}
249 		if (fido_dev_get_cbor_info_wait(dev, info, ms) != FIDO_OK) {
250 			fido_log_debug("%s: falling back to u2f", __func__);
251 			fido_dev_force_u2f(dev);
252 		} else {
253 			fido_dev_set_flags(dev, info);
254 		}
255 	}
256 
257 	if (fido_dev_is_fido2(dev) && info != NULL) {
258 		fido_log_debug("%s: FIDO_MAXMSG=%d, maxmsgsiz=%lu", __func__,
259 		    FIDO_MAXMSG, (unsigned long)fido_cbor_info_maxmsgsiz(info));
260 	}
261 
262 	r = FIDO_OK;
263 fail:
264 	fido_cbor_info_free(&info);
265 
266 	if (r != FIDO_OK) {
267 		dev->io.close(dev->io_handle);
268 		dev->io_handle = NULL;
269 	}
270 
271 	return (r);
272 }
273 
274 static int
275 fido_dev_open_wait(fido_dev_t *dev, const char *path, int ms)
276 {
277 	int r;
278 
279 	if ((r = fido_dev_open_tx(dev, path)) != FIDO_OK ||
280 	    (r = fido_dev_open_rx(dev, ms)) != FIDO_OK)
281 		return (r);
282 
283 	return (FIDO_OK);
284 }
285 
286 int
287 fido_dev_register_manifest_func(const dev_manifest_func_t f)
288 {
289 	dev_manifest_func_node_t *prev, *curr, *n;
290 
291 	find_manifest_func_node(f, &curr, &prev);
292 	if (curr != NULL)
293 		return (FIDO_OK);
294 
295 	if ((n = calloc(1, sizeof(*n))) == NULL) {
296 		fido_log_debug("%s: calloc", __func__);
297 		return (FIDO_ERR_INTERNAL);
298 	}
299 
300 	n->manifest_func = f;
301 	n->next = manifest_funcs;
302 	manifest_funcs = n;
303 
304 	return (FIDO_OK);
305 }
306 
307 void
308 fido_dev_unregister_manifest_func(const dev_manifest_func_t f)
309 {
310 	dev_manifest_func_node_t *prev, *curr;
311 
312 	find_manifest_func_node(f, &curr, &prev);
313 	if (curr == NULL)
314 		return;
315 	if (prev != NULL)
316 		prev->next = curr->next;
317 	else
318 		manifest_funcs = curr->next;
319 
320 	free(curr);
321 }
322 
323 int
324 fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
325 {
326 	dev_manifest_func_node_t	*curr = NULL;
327 	dev_manifest_func_t		 m_func;
328 	size_t				 curr_olen;
329 	int				 r;
330 
331 	*olen = 0;
332 
333 	if (fido_dev_register_manifest_func(fido_hid_manifest) != FIDO_OK)
334 		return (FIDO_ERR_INTERNAL);
335 
336 	for (curr = manifest_funcs; curr != NULL; curr = curr->next) {
337 		curr_olen = 0;
338 		m_func = curr->manifest_func;
339 		r = m_func(devlist + *olen, ilen - *olen, &curr_olen);
340 		if (r != FIDO_OK)
341 			return (r);
342 		*olen += curr_olen;
343 		if (*olen == ilen)
344 			break;
345 	}
346 
347 	return (FIDO_OK);
348 }
349 
350 int
351 fido_dev_open_with_info(fido_dev_t *dev)
352 {
353 	if (dev->path == NULL)
354 		return (FIDO_ERR_INVALID_ARGUMENT);
355 
356 	return (fido_dev_open_wait(dev, dev->path, -1));
357 }
358 
359 int
360 fido_dev_open(fido_dev_t *dev, const char *path)
361 {
362 	return (fido_dev_open_wait(dev, path, -1));
363 }
364 
365 int
366 fido_dev_close(fido_dev_t *dev)
367 {
368 	if (dev->io_handle == NULL || dev->io.close == NULL)
369 		return (FIDO_ERR_INVALID_ARGUMENT);
370 
371 	dev->io.close(dev->io_handle);
372 	dev->io_handle = NULL;
373 
374 	return (FIDO_OK);
375 }
376 
377 int
378 fido_dev_cancel(fido_dev_t *dev)
379 {
380 	if (fido_dev_is_fido2(dev) == false)
381 		return (FIDO_ERR_INVALID_ARGUMENT);
382 
383 	if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0) < 0)
384 		return (FIDO_ERR_TX);
385 
386 	return (FIDO_OK);
387 }
388 
389 int
390 fido_dev_get_touch_begin(fido_dev_t *dev)
391 {
392 	fido_blob_t	 f;
393 	cbor_item_t	*argv[9];
394 	const char	*clientdata = FIDO_DUMMY_CLIENTDATA;
395 	const uint8_t	 user_id = FIDO_DUMMY_USER_ID;
396 	unsigned char	 cdh[SHA256_DIGEST_LENGTH];
397 	fido_rp_t	 rp;
398 	fido_user_t	 user;
399 	int		 r = FIDO_ERR_INTERNAL;
400 
401 	memset(&f, 0, sizeof(f));
402 	memset(argv, 0, sizeof(argv));
403 	memset(cdh, 0, sizeof(cdh));
404 	memset(&rp, 0, sizeof(rp));
405 	memset(&user, 0, sizeof(user));
406 
407 	if (fido_dev_is_fido2(dev) == false)
408 		return (u2f_get_touch_begin(dev));
409 
410 	if (SHA256((const void *)clientdata, strlen(clientdata), cdh) != cdh) {
411 		fido_log_debug("%s: sha256", __func__);
412 		return (FIDO_ERR_INTERNAL);
413 	}
414 
415 	if ((rp.id = strdup(FIDO_DUMMY_RP_ID)) == NULL ||
416 	    (user.name = strdup(FIDO_DUMMY_USER_NAME)) == NULL) {
417 		fido_log_debug("%s: strdup", __func__);
418 		goto fail;
419 	}
420 
421 	if (fido_blob_set(&user.id, &user_id, sizeof(user_id)) < 0) {
422 		fido_log_debug("%s: fido_blob_set", __func__);
423 		goto fail;
424 	}
425 
426 	if ((argv[0] = cbor_build_bytestring(cdh, sizeof(cdh))) == NULL ||
427 	    (argv[1] = cbor_encode_rp_entity(&rp)) == NULL ||
428 	    (argv[2] = cbor_encode_user_entity(&user)) == NULL ||
429 	    (argv[3] = cbor_encode_pubkey_param(COSE_ES256)) == NULL) {
430 		fido_log_debug("%s: cbor encode", __func__);
431 		goto fail;
432 	}
433 
434 	if (fido_dev_supports_pin(dev)) {
435 		if ((argv[7] = cbor_new_definite_bytestring()) == NULL ||
436 		    (argv[8] = cbor_encode_pin_opt()) == NULL) {
437 			fido_log_debug("%s: cbor encode", __func__);
438 			goto fail;
439 		}
440 	}
441 
442 	if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, nitems(argv), &f) < 0 ||
443 	    fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
444 		fido_log_debug("%s: fido_tx", __func__);
445 		r = FIDO_ERR_TX;
446 		goto fail;
447 	}
448 
449 	r = FIDO_OK;
450 fail:
451 	cbor_vector_free(argv, nitems(argv));
452 	free(f.ptr);
453 	free(rp.id);
454 	free(user.name);
455 	free(user.id.ptr);
456 
457 	return (r);
458 }
459 
460 int
461 fido_dev_get_touch_status(fido_dev_t *dev, int *touched, int ms)
462 {
463 	int r;
464 
465 	*touched = 0;
466 
467 	if (fido_dev_is_fido2(dev) == false)
468 		return (u2f_get_touch_status(dev, touched, ms));
469 
470 	switch ((r = fido_rx_cbor_status(dev, ms))) {
471 	case FIDO_ERR_PIN_AUTH_INVALID:
472 	case FIDO_ERR_PIN_INVALID:
473 	case FIDO_ERR_PIN_NOT_SET:
474 	case FIDO_ERR_SUCCESS:
475 		*touched = 1;
476 		break;
477 	case FIDO_ERR_RX:
478 		/* ignore */
479 		break;
480 	default:
481 		fido_log_debug("%s: fido_rx_cbor_status", __func__);
482 		return (r);
483 	}
484 
485 	return (FIDO_OK);
486 }
487 
488 int
489 fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io)
490 {
491 	if (dev->io_handle != NULL) {
492 		fido_log_debug("%s: non-NULL handle", __func__);
493 		return (FIDO_ERR_INVALID_ARGUMENT);
494 	}
495 
496 	if (io == NULL || io->open == NULL || io->close == NULL ||
497 	    io->read == NULL || io->write == NULL) {
498 		fido_log_debug("%s: NULL function", __func__);
499 		return (FIDO_ERR_INVALID_ARGUMENT);
500 	}
501 
502 	dev->io = *io;
503 	dev->io_own = true;
504 
505 	return (FIDO_OK);
506 }
507 
508 int
509 fido_dev_set_transport_functions(fido_dev_t *dev, const fido_dev_transport_t *t)
510 {
511 	if (dev->io_handle != NULL) {
512 		fido_log_debug("%s: non-NULL handle", __func__);
513 		return (FIDO_ERR_INVALID_ARGUMENT);
514 	}
515 
516 	dev->transport = *t;
517 	dev->io_own = true;
518 
519 	return (FIDO_OK);
520 }
521 
522 void
523 fido_init(int flags)
524 {
525 	if (flags & FIDO_DEBUG || getenv("FIDO_DEBUG") != NULL)
526 		fido_log_init();
527 }
528 
529 fido_dev_t *
530 fido_dev_new(void)
531 {
532 	fido_dev_t *dev;
533 
534 	if ((dev = calloc(1, sizeof(*dev))) == NULL)
535 		return (NULL);
536 
537 	dev->cid = CTAP_CID_BROADCAST;
538 	dev->io = (fido_dev_io_t) {
539 		&fido_hid_open,
540 		&fido_hid_close,
541 		&fido_hid_read,
542 		&fido_hid_write,
543 	};
544 
545 	return (dev);
546 }
547 
548 fido_dev_t *
549 fido_dev_new_with_info(const fido_dev_info_t *di)
550 {
551 	fido_dev_t *dev;
552 
553 	if ((dev = calloc(1, sizeof(*dev))) == NULL)
554 		return (NULL);
555 
556 	dev->cid = CTAP_CID_BROADCAST;
557 
558 	if (di->io.open == NULL || di->io.close == NULL ||
559 	    di->io.read == NULL || di->io.write == NULL) {
560 		fido_log_debug("%s: NULL function", __func__);
561 		fido_dev_free(&dev);
562 		return (NULL);
563 	}
564 
565 	dev->io = di->io;
566 	dev->transport = di->transport;
567 
568 	if ((dev->path = strdup(di->path)) == NULL) {
569 		fido_log_debug("%s: strdup", __func__);
570 		fido_dev_free(&dev);
571 		return (NULL);
572 	}
573 
574 	return (dev);
575 }
576 
577 void
578 fido_dev_free(fido_dev_t **dev_p)
579 {
580 	fido_dev_t *dev;
581 
582 	if (dev_p == NULL || (dev = *dev_p) == NULL)
583 		return;
584 
585 	free(dev->path);
586 	free(dev);
587 
588 	*dev_p = NULL;
589 }
590 
591 uint8_t
592 fido_dev_protocol(const fido_dev_t *dev)
593 {
594 	return (dev->attr.protocol);
595 }
596 
597 uint8_t
598 fido_dev_major(const fido_dev_t *dev)
599 {
600 	return (dev->attr.major);
601 }
602 
603 uint8_t
604 fido_dev_minor(const fido_dev_t *dev)
605 {
606 	return (dev->attr.minor);
607 }
608 
609 uint8_t
610 fido_dev_build(const fido_dev_t *dev)
611 {
612 	return (dev->attr.build);
613 }
614 
615 uint8_t
616 fido_dev_flags(const fido_dev_t *dev)
617 {
618 	return (dev->attr.flags);
619 }
620 
621 bool
622 fido_dev_is_fido2(const fido_dev_t *dev)
623 {
624 	return (dev->attr.flags & FIDO_CAP_CBOR);
625 }
626 
627 bool
628 fido_dev_supports_pin(const fido_dev_t *dev)
629 {
630 	return (dev->flags & (FIDO_DEV_PIN_SET|FIDO_DEV_PIN_UNSET));
631 }
632 
633 bool
634 fido_dev_has_pin(const fido_dev_t *dev)
635 {
636 	return (dev->flags & FIDO_DEV_PIN_SET);
637 }
638 
639 bool
640 fido_dev_supports_cred_prot(const fido_dev_t *dev)
641 {
642 	return (dev->flags & FIDO_DEV_CRED_PROT);
643 }
644 
645 void
646 fido_dev_force_u2f(fido_dev_t *dev)
647 {
648 	dev->attr.flags &= (uint8_t)~FIDO_CAP_CBOR;
649 	dev->flags = 0;
650 }
651 
652 void
653 fido_dev_force_fido2(fido_dev_t *dev)
654 {
655 	dev->attr.flags |= FIDO_CAP_CBOR;
656 }
657