Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libfido2/src/hid_hidapi.c
39483 views
1
/*
2
* Copyright (c) 2019 Google LLC. 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
* SPDX-License-Identifier: BSD-2-Clause
6
*/
7
8
#ifdef __linux__
9
#include <sys/ioctl.h>
10
#include <linux/hidraw.h>
11
#include <linux/input.h>
12
#include <fcntl.h>
13
#endif
14
15
#include <errno.h>
16
#include <hidapi.h>
17
#include <wchar.h>
18
19
#include "fido.h"
20
21
struct hid_hidapi {
22
void *handle;
23
size_t report_in_len;
24
size_t report_out_len;
25
};
26
27
static size_t
28
fido_wcslen(const wchar_t *wcs)
29
{
30
size_t l = 0;
31
while (*wcs++ != L'\0')
32
l++;
33
return l;
34
}
35
36
static char *
37
wcs_to_cs(const wchar_t *wcs)
38
{
39
char *cs;
40
size_t i;
41
42
if (wcs == NULL || (cs = calloc(fido_wcslen(wcs) + 1, 1)) == NULL)
43
return NULL;
44
45
for (i = 0; i < fido_wcslen(wcs); i++) {
46
if (wcs[i] >= 128) {
47
/* give up on parsing non-ASCII text */
48
free(cs);
49
return strdup("hidapi device");
50
}
51
cs[i] = (char)wcs[i];
52
}
53
54
return cs;
55
}
56
57
static int
58
copy_info(fido_dev_info_t *di, const struct hid_device_info *d)
59
{
60
memset(di, 0, sizeof(*di));
61
62
if (d->path != NULL)
63
di->path = strdup(d->path);
64
else
65
di->path = strdup("");
66
67
if (d->manufacturer_string != NULL)
68
di->manufacturer = wcs_to_cs(d->manufacturer_string);
69
else
70
di->manufacturer = strdup("");
71
72
if (d->product_string != NULL)
73
di->product = wcs_to_cs(d->product_string);
74
else
75
di->product = strdup("");
76
77
if (di->path == NULL ||
78
di->manufacturer == NULL ||
79
di->product == NULL) {
80
free(di->path);
81
free(di->manufacturer);
82
free(di->product);
83
explicit_bzero(di, sizeof(*di));
84
return -1;
85
}
86
87
di->product_id = (int16_t)d->product_id;
88
di->vendor_id = (int16_t)d->vendor_id;
89
di->io = (fido_dev_io_t) {
90
&fido_hid_open,
91
&fido_hid_close,
92
&fido_hid_read,
93
&fido_hid_write,
94
};
95
96
return 0;
97
}
98
99
#ifdef __linux__
100
static int
101
get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd)
102
{
103
int fd;
104
int s = -1;
105
int ok = -1;
106
107
if ((fd = fido_hid_unix_open(path)) == -1) {
108
fido_log_debug("%s: fido_hid_unix_open", __func__);
109
return -1;
110
}
111
112
if (ioctl(fd, IOCTL_REQ(HIDIOCGRDESCSIZE), &s) < 0 || s < 0 ||
113
(unsigned)s > HID_MAX_DESCRIPTOR_SIZE) {
114
fido_log_error(errno, "%s: ioctl HIDIOCGRDESCSIZE", __func__);
115
goto fail;
116
}
117
118
hrd->size = (unsigned)s;
119
120
if (ioctl(fd, IOCTL_REQ(HIDIOCGRDESC), hrd) < 0) {
121
fido_log_error(errno, "%s: ioctl HIDIOCGRDESC", __func__);
122
goto fail;
123
}
124
125
ok = 0;
126
fail:
127
if (fd != -1)
128
close(fd);
129
130
return ok;
131
}
132
133
static bool
134
is_fido(const struct hid_device_info *hdi)
135
{
136
uint32_t usage_page = 0;
137
struct hidraw_report_descriptor *hrd;
138
139
if ((hrd = calloc(1, sizeof(*hrd))) == NULL ||
140
get_report_descriptor(hdi->path, hrd) < 0 ||
141
fido_hid_get_usage(hrd->value, hrd->size, &usage_page) < 0)
142
usage_page = 0;
143
144
free(hrd);
145
146
return usage_page == 0xf1d0;
147
}
148
#elif defined(_WIN32) || defined(__APPLE__)
149
static bool
150
is_fido(const struct hid_device_info *hdi)
151
{
152
return hdi->usage_page == 0xf1d0;
153
}
154
#else
155
static bool
156
is_fido(const struct hid_device_info *hdi)
157
{
158
(void)hdi;
159
fido_log_debug("%s: assuming FIDO HID", __func__);
160
return true;
161
}
162
#endif
163
164
void *
165
fido_hid_open(const char *path)
166
{
167
struct hid_hidapi *ctx;
168
169
if ((ctx = calloc(1, sizeof(*ctx))) == NULL) {
170
return (NULL);
171
}
172
173
if ((ctx->handle = hid_open_path(path)) == NULL) {
174
free(ctx);
175
return (NULL);
176
}
177
178
ctx->report_in_len = ctx->report_out_len = CTAP_MAX_REPORT_LEN;
179
180
return ctx;
181
}
182
183
void
184
fido_hid_close(void *handle)
185
{
186
struct hid_hidapi *ctx = handle;
187
188
hid_close(ctx->handle);
189
free(ctx);
190
}
191
192
int
193
fido_hid_set_sigmask(void *handle, const fido_sigset_t *sigmask)
194
{
195
(void)handle;
196
(void)sigmask;
197
198
return (FIDO_ERR_INTERNAL);
199
}
200
201
int
202
fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms)
203
{
204
struct hid_hidapi *ctx = handle;
205
206
if (len != ctx->report_in_len) {
207
fido_log_debug("%s: len %zu", __func__, len);
208
return -1;
209
}
210
211
return hid_read_timeout(ctx->handle, buf, len, ms);
212
}
213
214
int
215
fido_hid_write(void *handle, const unsigned char *buf, size_t len)
216
{
217
struct hid_hidapi *ctx = handle;
218
219
if (len != ctx->report_out_len + 1) {
220
fido_log_debug("%s: len %zu", __func__, len);
221
return -1;
222
}
223
224
return hid_write(ctx->handle, buf, len);
225
}
226
227
int
228
fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
229
{
230
struct hid_device_info *hdi;
231
232
*olen = 0;
233
234
if (ilen == 0)
235
return FIDO_OK; /* nothing to do */
236
if (devlist == NULL)
237
return FIDO_ERR_INVALID_ARGUMENT;
238
if ((hdi = hid_enumerate(0, 0)) == NULL)
239
return FIDO_OK; /* nothing to do */
240
241
for (struct hid_device_info *d = hdi; d != NULL; d = d->next) {
242
if (is_fido(d) == false)
243
continue;
244
if (copy_info(&devlist[*olen], d) == 0) {
245
if (++(*olen) == ilen)
246
break;
247
}
248
}
249
250
hid_free_enumeration(hdi);
251
252
return FIDO_OK;
253
}
254
255
size_t
256
fido_hid_report_in_len(void *handle)
257
{
258
struct hid_hidapi *ctx = handle;
259
260
return (ctx->report_in_len);
261
}
262
263
size_t
264
fido_hid_report_out_len(void *handle)
265
{
266
struct hid_hidapi *ctx = handle;
267
268
return (ctx->report_out_len);
269
}
270
271