xref: /freebsd-src/contrib/libfido2/src/hid.c (revision 2ccfa855b2fc331819953e3de1b1c15ce5b95a7e)
10afa8e06SEd Maste /*
20afa8e06SEd Maste  * Copyright (c) 2018 Yubico AB. All rights reserved.
30afa8e06SEd Maste  * Use of this source code is governed by a BSD-style
40afa8e06SEd Maste  * license that can be found in the LICENSE file.
5*2ccfa855SEd Maste  * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste  */
70afa8e06SEd Maste 
80afa8e06SEd Maste #include "fido.h"
90afa8e06SEd Maste 
100afa8e06SEd Maste static int
get_key_len(uint8_t tag,uint8_t * key,size_t * key_len)110afa8e06SEd Maste get_key_len(uint8_t tag, uint8_t *key, size_t *key_len)
120afa8e06SEd Maste {
130afa8e06SEd Maste 	*key = tag & 0xfc;
140afa8e06SEd Maste 	if ((*key & 0xf0) == 0xf0) {
150afa8e06SEd Maste 		fido_log_debug("%s: *key=0x%02x", __func__, *key);
160afa8e06SEd Maste 		return (-1);
170afa8e06SEd Maste 	}
180afa8e06SEd Maste 
190afa8e06SEd Maste 	*key_len = tag & 0x3;
200afa8e06SEd Maste 	if (*key_len == 3) {
210afa8e06SEd Maste 		*key_len = 4;
220afa8e06SEd Maste 	}
230afa8e06SEd Maste 
240afa8e06SEd Maste 	return (0);
250afa8e06SEd Maste }
260afa8e06SEd Maste 
270afa8e06SEd Maste static int
get_key_val(const void * body,size_t key_len,uint32_t * val)280afa8e06SEd Maste get_key_val(const void *body, size_t key_len, uint32_t *val)
290afa8e06SEd Maste {
300afa8e06SEd Maste 	const uint8_t *ptr = body;
310afa8e06SEd Maste 
320afa8e06SEd Maste 	switch (key_len) {
330afa8e06SEd Maste 	case 0:
340afa8e06SEd Maste 		*val = 0;
350afa8e06SEd Maste 		break;
360afa8e06SEd Maste 	case 1:
370afa8e06SEd Maste 		*val = ptr[0];
380afa8e06SEd Maste 		break;
390afa8e06SEd Maste 	case 2:
400afa8e06SEd Maste 		*val = (uint32_t)((ptr[1] << 8) | ptr[0]);
410afa8e06SEd Maste 		break;
420afa8e06SEd Maste 	default:
430afa8e06SEd Maste 		fido_log_debug("%s: key_len=%zu", __func__, key_len);
440afa8e06SEd Maste 		return (-1);
450afa8e06SEd Maste 	}
460afa8e06SEd Maste 
470afa8e06SEd Maste 	return (0);
480afa8e06SEd Maste }
490afa8e06SEd Maste 
500afa8e06SEd Maste int
fido_hid_get_usage(const uint8_t * report_ptr,size_t report_len,uint32_t * usage_page)510afa8e06SEd Maste fido_hid_get_usage(const uint8_t *report_ptr, size_t report_len,
520afa8e06SEd Maste     uint32_t *usage_page)
530afa8e06SEd Maste {
540afa8e06SEd Maste 	const uint8_t	*ptr = report_ptr;
550afa8e06SEd Maste 	size_t		 len = report_len;
560afa8e06SEd Maste 
570afa8e06SEd Maste 	while (len > 0) {
580afa8e06SEd Maste 		const uint8_t tag = ptr[0];
590afa8e06SEd Maste 		ptr++;
600afa8e06SEd Maste 		len--;
610afa8e06SEd Maste 
620afa8e06SEd Maste 		uint8_t  key;
630afa8e06SEd Maste 		size_t   key_len;
640afa8e06SEd Maste 		uint32_t key_val;
650afa8e06SEd Maste 
660afa8e06SEd Maste 		if (get_key_len(tag, &key, &key_len) < 0 || key_len > len ||
670afa8e06SEd Maste 		    get_key_val(ptr, key_len, &key_val) < 0) {
680afa8e06SEd Maste 			return (-1);
690afa8e06SEd Maste 		}
700afa8e06SEd Maste 
710afa8e06SEd Maste 		if (key == 0x4) {
720afa8e06SEd Maste 			*usage_page = key_val;
730afa8e06SEd Maste 		}
740afa8e06SEd Maste 
750afa8e06SEd Maste 		ptr += key_len;
760afa8e06SEd Maste 		len -= key_len;
770afa8e06SEd Maste 	}
780afa8e06SEd Maste 
790afa8e06SEd Maste 	return (0);
800afa8e06SEd Maste }
810afa8e06SEd Maste 
820afa8e06SEd Maste int
fido_hid_get_report_len(const uint8_t * report_ptr,size_t report_len,size_t * report_in_len,size_t * report_out_len)830afa8e06SEd Maste fido_hid_get_report_len(const uint8_t *report_ptr, size_t report_len,
840afa8e06SEd Maste     size_t *report_in_len, size_t *report_out_len)
850afa8e06SEd Maste {
860afa8e06SEd Maste 	const uint8_t	*ptr = report_ptr;
870afa8e06SEd Maste 	size_t		 len = report_len;
880afa8e06SEd Maste 	uint32_t	 report_size = 0;
890afa8e06SEd Maste 
900afa8e06SEd Maste 	while (len > 0) {
910afa8e06SEd Maste 		const uint8_t tag = ptr[0];
920afa8e06SEd Maste 		ptr++;
930afa8e06SEd Maste 		len--;
940afa8e06SEd Maste 
950afa8e06SEd Maste 		uint8_t  key;
960afa8e06SEd Maste 		size_t   key_len;
970afa8e06SEd Maste 		uint32_t key_val;
980afa8e06SEd Maste 
990afa8e06SEd Maste 		if (get_key_len(tag, &key, &key_len) < 0 || key_len > len ||
1000afa8e06SEd Maste 		    get_key_val(ptr, key_len, &key_val) < 0) {
1010afa8e06SEd Maste 			return (-1);
1020afa8e06SEd Maste 		}
1030afa8e06SEd Maste 
1040afa8e06SEd Maste 		if (key == 0x94) {
1050afa8e06SEd Maste 			report_size = key_val;
1060afa8e06SEd Maste 		} else if (key == 0x80) {
1070afa8e06SEd Maste 			*report_in_len = (size_t)report_size;
1080afa8e06SEd Maste 		} else if (key == 0x90) {
1090afa8e06SEd Maste 			*report_out_len = (size_t)report_size;
1100afa8e06SEd Maste 		}
1110afa8e06SEd Maste 
1120afa8e06SEd Maste 		ptr += key_len;
1130afa8e06SEd Maste 		len -= key_len;
1140afa8e06SEd Maste 	}
1150afa8e06SEd Maste 
1160afa8e06SEd Maste 	return (0);
1170afa8e06SEd Maste }
1180afa8e06SEd Maste 
1190afa8e06SEd Maste fido_dev_info_t *
fido_dev_info_new(size_t n)1200afa8e06SEd Maste fido_dev_info_new(size_t n)
1210afa8e06SEd Maste {
1220afa8e06SEd Maste 	return (calloc(n, sizeof(fido_dev_info_t)));
1230afa8e06SEd Maste }
1240afa8e06SEd Maste 
1253e696dfbSEd Maste static void
fido_dev_info_reset(fido_dev_info_t * di)1263e696dfbSEd Maste fido_dev_info_reset(fido_dev_info_t *di)
1273e696dfbSEd Maste {
1283e696dfbSEd Maste 	free(di->path);
1293e696dfbSEd Maste 	free(di->manufacturer);
1303e696dfbSEd Maste 	free(di->product);
1313e696dfbSEd Maste 	memset(di, 0, sizeof(*di));
1323e696dfbSEd Maste }
1333e696dfbSEd Maste 
1340afa8e06SEd Maste void
fido_dev_info_free(fido_dev_info_t ** devlist_p,size_t n)1350afa8e06SEd Maste fido_dev_info_free(fido_dev_info_t **devlist_p, size_t n)
1360afa8e06SEd Maste {
1370afa8e06SEd Maste 	fido_dev_info_t *devlist;
1380afa8e06SEd Maste 
1390afa8e06SEd Maste 	if (devlist_p == NULL || (devlist = *devlist_p) == NULL)
1400afa8e06SEd Maste 		return;
1410afa8e06SEd Maste 
1423e696dfbSEd Maste 	for (size_t i = 0; i < n; i++)
1433e696dfbSEd Maste 		fido_dev_info_reset(&devlist[i]);
1440afa8e06SEd Maste 
1450afa8e06SEd Maste 	free(devlist);
1460afa8e06SEd Maste 
1470afa8e06SEd Maste 	*devlist_p = NULL;
1480afa8e06SEd Maste }
1490afa8e06SEd Maste 
1500afa8e06SEd Maste const fido_dev_info_t *
fido_dev_info_ptr(const fido_dev_info_t * devlist,size_t i)1510afa8e06SEd Maste fido_dev_info_ptr(const fido_dev_info_t *devlist, size_t i)
1520afa8e06SEd Maste {
1530afa8e06SEd Maste 	return (&devlist[i]);
1540afa8e06SEd Maste }
1550afa8e06SEd Maste 
1563e696dfbSEd Maste int
fido_dev_info_set(fido_dev_info_t * devlist,size_t i,const char * path,const char * manufacturer,const char * product,const fido_dev_io_t * io,const fido_dev_transport_t * transport)1573e696dfbSEd Maste fido_dev_info_set(fido_dev_info_t *devlist, size_t i,
1583e696dfbSEd Maste     const char *path, const char *manufacturer, const char *product,
1593e696dfbSEd Maste     const fido_dev_io_t *io, const fido_dev_transport_t *transport)
1603e696dfbSEd Maste {
1613e696dfbSEd Maste 	char *path_copy = NULL, *manu_copy = NULL, *prod_copy = NULL;
1623e696dfbSEd Maste 	int r;
1633e696dfbSEd Maste 
1643e696dfbSEd Maste 	if (path == NULL || manufacturer == NULL || product == NULL ||
1653e696dfbSEd Maste 	    io == NULL) {
1663e696dfbSEd Maste 		r = FIDO_ERR_INVALID_ARGUMENT;
1673e696dfbSEd Maste 		goto out;
1683e696dfbSEd Maste 	}
1693e696dfbSEd Maste 
1703e696dfbSEd Maste 	if ((path_copy = strdup(path)) == NULL ||
1713e696dfbSEd Maste 	    (manu_copy = strdup(manufacturer)) == NULL ||
1723e696dfbSEd Maste 	    (prod_copy = strdup(product)) == NULL) {
1733e696dfbSEd Maste 		r = FIDO_ERR_INTERNAL;
1743e696dfbSEd Maste 		goto out;
1753e696dfbSEd Maste 	}
1763e696dfbSEd Maste 
1773e696dfbSEd Maste 	fido_dev_info_reset(&devlist[i]);
1783e696dfbSEd Maste 	devlist[i].path = path_copy;
1793e696dfbSEd Maste 	devlist[i].manufacturer = manu_copy;
1803e696dfbSEd Maste 	devlist[i].product = prod_copy;
1813e696dfbSEd Maste 	devlist[i].io = *io;
1823e696dfbSEd Maste 	if (transport)
1833e696dfbSEd Maste 		devlist[i].transport = *transport;
1843e696dfbSEd Maste 	r = FIDO_OK;
1853e696dfbSEd Maste out:
1863e696dfbSEd Maste 	if (r != FIDO_OK) {
1873e696dfbSEd Maste 		free(prod_copy);
1883e696dfbSEd Maste 		free(manu_copy);
1893e696dfbSEd Maste 		free(path_copy);
1903e696dfbSEd Maste 	}
1913e696dfbSEd Maste 	return (r);
1923e696dfbSEd Maste }
1933e696dfbSEd Maste 
1940afa8e06SEd Maste const char *
fido_dev_info_path(const fido_dev_info_t * di)1950afa8e06SEd Maste fido_dev_info_path(const fido_dev_info_t *di)
1960afa8e06SEd Maste {
1970afa8e06SEd Maste 	return (di->path);
1980afa8e06SEd Maste }
1990afa8e06SEd Maste 
2000afa8e06SEd Maste int16_t
fido_dev_info_vendor(const fido_dev_info_t * di)2010afa8e06SEd Maste fido_dev_info_vendor(const fido_dev_info_t *di)
2020afa8e06SEd Maste {
2030afa8e06SEd Maste 	return (di->vendor_id);
2040afa8e06SEd Maste }
2050afa8e06SEd Maste 
2060afa8e06SEd Maste int16_t
fido_dev_info_product(const fido_dev_info_t * di)2070afa8e06SEd Maste fido_dev_info_product(const fido_dev_info_t *di)
2080afa8e06SEd Maste {
2090afa8e06SEd Maste 	return (di->product_id);
2100afa8e06SEd Maste }
2110afa8e06SEd Maste 
2120afa8e06SEd Maste const char *
fido_dev_info_manufacturer_string(const fido_dev_info_t * di)2130afa8e06SEd Maste fido_dev_info_manufacturer_string(const fido_dev_info_t *di)
2140afa8e06SEd Maste {
2150afa8e06SEd Maste 	return (di->manufacturer);
2160afa8e06SEd Maste }
2170afa8e06SEd Maste 
2180afa8e06SEd Maste const char *
fido_dev_info_product_string(const fido_dev_info_t * di)2190afa8e06SEd Maste fido_dev_info_product_string(const fido_dev_info_t *di)
2200afa8e06SEd Maste {
2210afa8e06SEd Maste 	return (di->product);
2220afa8e06SEd Maste }
223