Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
yubihsm_libusb.c
Go to the documentation of this file.
1/*
2 * Copyright 2015-2018 Yubico AB
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <libusb.h>
18
19#include <string.h>
20
21#include "yubihsm.h"
22#include "internal.h"
23#include "yubihsm_usb.h"
24#include "debug_lib.h"
25
26#ifdef NO_LIBUSB_STRERROR
27#define libusb_strerror(x) libusb_error_name(x)
28#endif
29
30struct state {
31 libusb_context *ctx;
32 libusb_device_handle *handle;
33 unsigned long serial;
34};
35
36void usb_set_serial(yh_backend *state, unsigned long serial) {
38}
39
41 if (state && state->handle) {
42 libusb_release_interface(state->handle, 0);
43 libusb_close(state->handle);
44 state->handle = NULL;
45 }
46}
47
49 if (state && *state) {
51 if ((*state)->ctx) {
52 libusb_exit((*state)->ctx);
53 (*state)->ctx = NULL;
54 }
55 free(*state);
56 *state = NULL;
57 }
58}
59
61 yh_backend *backend = calloc(1, sizeof(yh_backend));
62 if (backend) {
63 libusb_init(&backend->ctx);
64 }
65 return backend;
66}
67
69 libusb_device **list;
70 libusb_device_handle *h = NULL;
71 ssize_t cnt = libusb_get_device_list(backend->ctx, &list);
72
73 if (backend->handle) {
74 usb_close(backend);
75 }
76
77 if (cnt < 0) {
78 DBG_ERR("Failed to get device list: %s", libusb_strerror(cnt));
79 return NULL;
80 }
81
82 for (ssize_t i = 0; i < cnt; i++) {
83 struct libusb_device_descriptor desc;
84 int ret = libusb_get_device_descriptor(list[i], &desc);
85 if (ret != 0) {
86 DBG_INFO("Failed to get descriptor for device %zd: %s", i,
87 libusb_strerror(ret));
88 continue;
89 }
90 if (desc.idVendor == YH_VID && desc.idProduct == YH_PID) {
91 ret = libusb_open(list[i], &h);
92 if (ret != 0 || h == NULL) {
93 DBG_INFO("Failed to open device for index %zd: %s", i,
94 libusb_strerror(ret));
95 continue;
96 }
97 if (backend->serial != 0) {
98 unsigned char data[16] = {0};
99
100 ret = libusb_get_string_descriptor_ascii(h, desc.iSerialNumber, data,
101 sizeof(data));
102
103 unsigned long devSerial = strtoul((char *) data, NULL, 10);
104
105 if (devSerial != backend->serial) {
106 DBG_INFO("Device %zd has serial %lu, not matching searched %lu", i,
107 devSerial, backend->serial);
108 goto next;
109 }
110 }
111
112 ret = libusb_claim_interface(h, 0);
113 if (ret != 0) {
114 DBG_ERR("Failed to claim interface: %s of device %zd",
115 libusb_strerror(ret), i);
116 goto next;
117 }
118
119 break;
120 next:
121 libusb_close(h);
122 h = NULL;
123 }
124 }
125
126 libusb_free_device_list(list, 1);
127 backend->handle = h;
128 if (h) {
129 // we set up a dummy read with a 1ms timeout here. The reason for doing this
130 // is that there might be data left in th e device buffers from earlier
131 // transactions, this should flush it.
132 unsigned char buf[YH_MSG_BUF_SIZE];
133 int transferred = 0;
134 if (libusb_bulk_transfer(h, 0x81, buf, sizeof(buf), &transferred, 1) == 0) {
135 DBG_INFO("%d bytes of stale data read from device", transferred);
136 }
137 return true;
138 } else {
139 return false;
140 }
141}
142
143int usb_write(yh_backend *state, unsigned char *buf, long unsigned len) {
144 int transferred = 0;
145 if (state->handle == NULL) {
146 DBG_ERR("Handle is not connected");
147 return 0;
148 }
149 /* TODO: does this need to loop and transmit several times? */
150 int ret =
151 libusb_bulk_transfer(state->handle, 0x01, buf, len, &transferred, 0);
152 DBG_INFO("Write of %lu %d, err %d", len, transferred, ret);
153 if (ret != 0 || transferred != (int) len) {
154 DBG_ERR("Transferred did not match len of write %d-%lu", transferred, len);
155 return 0;
156 }
157 if (len % 64 == 0) {
158 /* this writes the ZLP */
159 ret = libusb_bulk_transfer(state->handle, 0x01, buf, 0, &transferred, 0);
160 if (ret != 0) {
161 return 0;
162 }
163 }
164 return 1;
165}
166
167int usb_read(yh_backend *state, unsigned char *buf, unsigned long *len) {
168 int transferred = 0;
169 int ret;
170
171 if (state->handle == NULL) {
172 DBG_ERR("Handle is not connected");
173 return 0;
174 }
175
176 DBG_INFO("Doing usb read");
177
178 /* TODO: does this need to loop for all data?*/
179 ret = libusb_bulk_transfer(state->handle, 0x81, buf, *len, &transferred, 0);
180 if (ret != 0) {
181 DBG_ERR("Failed usb_read with ret: %d", ret);
182 return 0;
183 }
184 DBG_INFO("Read, transfer %d", transferred);
185 *len = transferred;
186 return 1;
187}
#define DBG_ERR(...)
Definition debug_lib.h:76
#define DBG_INFO(...)
Definition debug_lib.h:63
unsigned long serial
libusb_context * ctx
libusb_device_handle * handle
#define YH_PID
Device product ID.
Definition yubihsm.h:99
#define YH_MSG_BUF_SIZE
Maximum length of message buffer.
Definition yubihsm.h:93
#define YH_VID
Device vendor ID.
Definition yubihsm.h:97
void usb_destroy(yh_backend **state)
void usb_close(yh_backend *state)
void usb_set_serial(yh_backend *state, unsigned long serial)
yh_backend * backend_create(void)
int usb_read(yh_backend *state, unsigned char *buf, unsigned long *len)
bool usb_open_device(yh_backend *backend)
int usb_write(yh_backend *state, unsigned char *buf, long unsigned len)
uint32_t serial
CK_RV ret
size_t len
uint8_t buf[2048]