1*2ccfa855SEd Maste /*
2*2ccfa855SEd Maste * Copyright (c) 2022 Micro Focus or one of its affiliates.
3*2ccfa855SEd Maste * Copyright (c) 2022 Yubico AB. All rights reserved.
4*2ccfa855SEd Maste * Use of this source code is governed by a BSD-style
5*2ccfa855SEd Maste * license that can be found in the LICENSE file.
6*2ccfa855SEd Maste * SPDX-License-Identifier: BSD-2-Clause
7*2ccfa855SEd Maste */
8*2ccfa855SEd Maste
9*2ccfa855SEd Maste #if __APPLE__
10*2ccfa855SEd Maste #include <PCSC/wintypes.h>
11*2ccfa855SEd Maste #include <PCSC/winscard.h>
12*2ccfa855SEd Maste #else
13*2ccfa855SEd Maste #include <winscard.h>
14*2ccfa855SEd Maste #endif /* __APPLE__ */
15*2ccfa855SEd Maste
16*2ccfa855SEd Maste #include <errno.h>
17*2ccfa855SEd Maste
18*2ccfa855SEd Maste #include "fido.h"
19*2ccfa855SEd Maste #include "fido/param.h"
20*2ccfa855SEd Maste #include "iso7816.h"
21*2ccfa855SEd Maste
22*2ccfa855SEd Maste #if defined(_WIN32) && !defined(__MINGW32__)
23*2ccfa855SEd Maste #define SCardConnect SCardConnectA
24*2ccfa855SEd Maste #define SCardListReaders SCardListReadersA
25*2ccfa855SEd Maste #endif
26*2ccfa855SEd Maste
27*2ccfa855SEd Maste #ifndef SCARD_PROTOCOL_Tx
28*2ccfa855SEd Maste #define SCARD_PROTOCOL_Tx SCARD_PROTOCOL_ANY
29*2ccfa855SEd Maste #endif
30*2ccfa855SEd Maste
31*2ccfa855SEd Maste #define BUFSIZE 1024 /* in bytes; passed to SCardListReaders() */
32*2ccfa855SEd Maste #define APDULEN 264 /* 261 rounded up to the nearest multiple of 8 */
33*2ccfa855SEd Maste #define READERS 8 /* maximum number of readers */
34*2ccfa855SEd Maste
35*2ccfa855SEd Maste struct pcsc {
36*2ccfa855SEd Maste SCARDCONTEXT ctx;
37*2ccfa855SEd Maste SCARDHANDLE h;
38*2ccfa855SEd Maste SCARD_IO_REQUEST req;
39*2ccfa855SEd Maste uint8_t rx_buf[APDULEN];
40*2ccfa855SEd Maste size_t rx_len;
41*2ccfa855SEd Maste };
42*2ccfa855SEd Maste
43*2ccfa855SEd Maste static LONG
list_readers(SCARDCONTEXT ctx,char ** buf)44*2ccfa855SEd Maste list_readers(SCARDCONTEXT ctx, char **buf)
45*2ccfa855SEd Maste {
46*2ccfa855SEd Maste LONG s;
47*2ccfa855SEd Maste DWORD len;
48*2ccfa855SEd Maste
49*2ccfa855SEd Maste len = BUFSIZE;
50*2ccfa855SEd Maste if ((*buf = calloc(1, len)) == NULL)
51*2ccfa855SEd Maste goto fail;
52*2ccfa855SEd Maste if ((s = SCardListReaders(ctx, NULL, *buf, &len)) != SCARD_S_SUCCESS) {
53*2ccfa855SEd Maste fido_log_debug("%s: SCardListReaders 0x%lx", __func__, (long)s);
54*2ccfa855SEd Maste goto fail;
55*2ccfa855SEd Maste }
56*2ccfa855SEd Maste /* sanity check "multi-string" */
57*2ccfa855SEd Maste if (len > BUFSIZE || len < 2) {
58*2ccfa855SEd Maste fido_log_debug("%s: bogus len=%u", __func__, (unsigned)len);
59*2ccfa855SEd Maste goto fail;
60*2ccfa855SEd Maste }
61*2ccfa855SEd Maste if ((*buf)[len - 1] != 0 || (*buf)[len - 2] != '\0') {
62*2ccfa855SEd Maste fido_log_debug("%s: bogus buf", __func__);
63*2ccfa855SEd Maste goto fail;
64*2ccfa855SEd Maste }
65*2ccfa855SEd Maste return (LONG)SCARD_S_SUCCESS;
66*2ccfa855SEd Maste fail:
67*2ccfa855SEd Maste free(*buf);
68*2ccfa855SEd Maste *buf = NULL;
69*2ccfa855SEd Maste
70*2ccfa855SEd Maste return (LONG)SCARD_E_NO_READERS_AVAILABLE;
71*2ccfa855SEd Maste }
72*2ccfa855SEd Maste
73*2ccfa855SEd Maste static char *
get_reader(SCARDCONTEXT ctx,const char * path)74*2ccfa855SEd Maste get_reader(SCARDCONTEXT ctx, const char *path)
75*2ccfa855SEd Maste {
76*2ccfa855SEd Maste char *reader = NULL, *buf = NULL;
77*2ccfa855SEd Maste const char prefix[] = FIDO_PCSC_PREFIX "//slot";
78*2ccfa855SEd Maste uint64_t n;
79*2ccfa855SEd Maste
80*2ccfa855SEd Maste if (path == NULL)
81*2ccfa855SEd Maste goto out;
82*2ccfa855SEd Maste if (strncmp(path, prefix, strlen(prefix)) != 0 ||
83*2ccfa855SEd Maste fido_to_uint64(path + strlen(prefix), 10, &n) < 0 ||
84*2ccfa855SEd Maste n > READERS - 1) {
85*2ccfa855SEd Maste fido_log_debug("%s: invalid path %s", __func__, path);
86*2ccfa855SEd Maste goto out;
87*2ccfa855SEd Maste }
88*2ccfa855SEd Maste if (list_readers(ctx, &buf) != SCARD_S_SUCCESS) {
89*2ccfa855SEd Maste fido_log_debug("%s: list_readers", __func__);
90*2ccfa855SEd Maste goto out;
91*2ccfa855SEd Maste }
92*2ccfa855SEd Maste for (const char *name = buf; *name != 0; name += strlen(name) + 1) {
93*2ccfa855SEd Maste if (n == 0) {
94*2ccfa855SEd Maste reader = strdup(name);
95*2ccfa855SEd Maste goto out;
96*2ccfa855SEd Maste }
97*2ccfa855SEd Maste n--;
98*2ccfa855SEd Maste }
99*2ccfa855SEd Maste fido_log_debug("%s: failed to find reader %s", __func__, path);
100*2ccfa855SEd Maste out:
101*2ccfa855SEd Maste free(buf);
102*2ccfa855SEd Maste
103*2ccfa855SEd Maste return reader;
104*2ccfa855SEd Maste }
105*2ccfa855SEd Maste
106*2ccfa855SEd Maste static int
prepare_io_request(DWORD prot,SCARD_IO_REQUEST * req)107*2ccfa855SEd Maste prepare_io_request(DWORD prot, SCARD_IO_REQUEST *req)
108*2ccfa855SEd Maste {
109*2ccfa855SEd Maste switch (prot) {
110*2ccfa855SEd Maste case SCARD_PROTOCOL_T0:
111*2ccfa855SEd Maste req->dwProtocol = SCARD_PCI_T0->dwProtocol;
112*2ccfa855SEd Maste req->cbPciLength = SCARD_PCI_T0->cbPciLength;
113*2ccfa855SEd Maste break;
114*2ccfa855SEd Maste case SCARD_PROTOCOL_T1:
115*2ccfa855SEd Maste req->dwProtocol = SCARD_PCI_T1->dwProtocol;
116*2ccfa855SEd Maste req->cbPciLength = SCARD_PCI_T1->cbPciLength;
117*2ccfa855SEd Maste break;
118*2ccfa855SEd Maste default:
119*2ccfa855SEd Maste fido_log_debug("%s: unknown protocol %lu", __func__,
120*2ccfa855SEd Maste (u_long)prot);
121*2ccfa855SEd Maste return -1;
122*2ccfa855SEd Maste }
123*2ccfa855SEd Maste
124*2ccfa855SEd Maste return 0;
125*2ccfa855SEd Maste }
126*2ccfa855SEd Maste
127*2ccfa855SEd Maste static int
copy_info(fido_dev_info_t * di,SCARDCONTEXT ctx,const char * reader,size_t idx)128*2ccfa855SEd Maste copy_info(fido_dev_info_t *di, SCARDCONTEXT ctx, const char *reader, size_t idx)
129*2ccfa855SEd Maste {
130*2ccfa855SEd Maste SCARDHANDLE h = 0;
131*2ccfa855SEd Maste SCARD_IO_REQUEST req;
132*2ccfa855SEd Maste DWORD prot = 0;
133*2ccfa855SEd Maste LONG s;
134*2ccfa855SEd Maste int ok = -1;
135*2ccfa855SEd Maste
136*2ccfa855SEd Maste memset(di, 0, sizeof(*di));
137*2ccfa855SEd Maste memset(&req, 0, sizeof(req));
138*2ccfa855SEd Maste
139*2ccfa855SEd Maste if ((s = SCardConnect(ctx, reader, SCARD_SHARE_SHARED,
140*2ccfa855SEd Maste SCARD_PROTOCOL_Tx, &h, &prot)) != SCARD_S_SUCCESS) {
141*2ccfa855SEd Maste fido_log_debug("%s: SCardConnect 0x%lx", __func__, (long)s);
142*2ccfa855SEd Maste goto fail;
143*2ccfa855SEd Maste }
144*2ccfa855SEd Maste if (prepare_io_request(prot, &req) < 0) {
145*2ccfa855SEd Maste fido_log_debug("%s: prepare_io_request", __func__);
146*2ccfa855SEd Maste goto fail;
147*2ccfa855SEd Maste }
148*2ccfa855SEd Maste if (asprintf(&di->path, "%s//slot%zu", FIDO_PCSC_PREFIX, idx) == -1) {
149*2ccfa855SEd Maste di->path = NULL;
150*2ccfa855SEd Maste fido_log_debug("%s: asprintf", __func__);
151*2ccfa855SEd Maste goto fail;
152*2ccfa855SEd Maste }
153*2ccfa855SEd Maste if (nfc_is_fido(di->path) == false) {
154*2ccfa855SEd Maste fido_log_debug("%s: nfc_is_fido: %s", __func__, di->path);
155*2ccfa855SEd Maste goto fail;
156*2ccfa855SEd Maste }
157*2ccfa855SEd Maste if ((di->manufacturer = strdup("PC/SC")) == NULL ||
158*2ccfa855SEd Maste (di->product = strdup(reader)) == NULL)
159*2ccfa855SEd Maste goto fail;
160*2ccfa855SEd Maste
161*2ccfa855SEd Maste ok = 0;
162*2ccfa855SEd Maste fail:
163*2ccfa855SEd Maste if (h != 0)
164*2ccfa855SEd Maste SCardDisconnect(h, SCARD_LEAVE_CARD);
165*2ccfa855SEd Maste if (ok < 0) {
166*2ccfa855SEd Maste free(di->path);
167*2ccfa855SEd Maste free(di->manufacturer);
168*2ccfa855SEd Maste free(di->product);
169*2ccfa855SEd Maste explicit_bzero(di, sizeof(*di));
170*2ccfa855SEd Maste }
171*2ccfa855SEd Maste
172*2ccfa855SEd Maste return ok;
173*2ccfa855SEd Maste }
174*2ccfa855SEd Maste
175*2ccfa855SEd Maste int
fido_pcsc_manifest(fido_dev_info_t * devlist,size_t ilen,size_t * olen)176*2ccfa855SEd Maste fido_pcsc_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
177*2ccfa855SEd Maste {
178*2ccfa855SEd Maste SCARDCONTEXT ctx = 0;
179*2ccfa855SEd Maste char *buf = NULL;
180*2ccfa855SEd Maste LONG s;
181*2ccfa855SEd Maste size_t idx = 0;
182*2ccfa855SEd Maste int r = FIDO_ERR_INTERNAL;
183*2ccfa855SEd Maste
184*2ccfa855SEd Maste *olen = 0;
185*2ccfa855SEd Maste
186*2ccfa855SEd Maste if (ilen == 0)
187*2ccfa855SEd Maste return FIDO_OK;
188*2ccfa855SEd Maste if (devlist == NULL)
189*2ccfa855SEd Maste return FIDO_ERR_INVALID_ARGUMENT;
190*2ccfa855SEd Maste
191*2ccfa855SEd Maste if ((s = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
192*2ccfa855SEd Maste &ctx)) != SCARD_S_SUCCESS || ctx == 0) {
193*2ccfa855SEd Maste fido_log_debug("%s: SCardEstablishContext 0x%lx", __func__,
194*2ccfa855SEd Maste (long)s);
195*2ccfa855SEd Maste if (s == (LONG)SCARD_E_NO_SERVICE ||
196*2ccfa855SEd Maste s == (LONG)SCARD_E_NO_SMARTCARD)
197*2ccfa855SEd Maste r = FIDO_OK; /* suppress error */
198*2ccfa855SEd Maste goto out;
199*2ccfa855SEd Maste }
200*2ccfa855SEd Maste if ((s = list_readers(ctx, &buf)) != SCARD_S_SUCCESS) {
201*2ccfa855SEd Maste fido_log_debug("%s: list_readers 0x%lx", __func__, (long)s);
202*2ccfa855SEd Maste if (s == (LONG)SCARD_E_NO_READERS_AVAILABLE)
203*2ccfa855SEd Maste r = FIDO_OK; /* suppress error */
204*2ccfa855SEd Maste goto out;
205*2ccfa855SEd Maste }
206*2ccfa855SEd Maste
207*2ccfa855SEd Maste for (const char *name = buf; *name != 0; name += strlen(name) + 1) {
208*2ccfa855SEd Maste if (idx == READERS) {
209*2ccfa855SEd Maste fido_log_debug("%s: stopping at %zu readers", __func__,
210*2ccfa855SEd Maste idx);
211*2ccfa855SEd Maste r = FIDO_OK;
212*2ccfa855SEd Maste goto out;
213*2ccfa855SEd Maste }
214*2ccfa855SEd Maste if (copy_info(&devlist[*olen], ctx, name, idx++) == 0) {
215*2ccfa855SEd Maste devlist[*olen].io = (fido_dev_io_t) {
216*2ccfa855SEd Maste fido_pcsc_open,
217*2ccfa855SEd Maste fido_pcsc_close,
218*2ccfa855SEd Maste fido_pcsc_read,
219*2ccfa855SEd Maste fido_pcsc_write,
220*2ccfa855SEd Maste };
221*2ccfa855SEd Maste devlist[*olen].transport = (fido_dev_transport_t) {
222*2ccfa855SEd Maste fido_pcsc_rx,
223*2ccfa855SEd Maste fido_pcsc_tx,
224*2ccfa855SEd Maste };
225*2ccfa855SEd Maste if (++(*olen) == ilen)
226*2ccfa855SEd Maste break;
227*2ccfa855SEd Maste }
228*2ccfa855SEd Maste }
229*2ccfa855SEd Maste
230*2ccfa855SEd Maste r = FIDO_OK;
231*2ccfa855SEd Maste out:
232*2ccfa855SEd Maste free(buf);
233*2ccfa855SEd Maste if (ctx != 0)
234*2ccfa855SEd Maste SCardReleaseContext(ctx);
235*2ccfa855SEd Maste
236*2ccfa855SEd Maste return r;
237*2ccfa855SEd Maste }
238*2ccfa855SEd Maste
239*2ccfa855SEd Maste void *
fido_pcsc_open(const char * path)240*2ccfa855SEd Maste fido_pcsc_open(const char *path)
241*2ccfa855SEd Maste {
242*2ccfa855SEd Maste char *reader = NULL;
243*2ccfa855SEd Maste struct pcsc *dev = NULL;
244*2ccfa855SEd Maste SCARDCONTEXT ctx = 0;
245*2ccfa855SEd Maste SCARDHANDLE h = 0;
246*2ccfa855SEd Maste SCARD_IO_REQUEST req;
247*2ccfa855SEd Maste DWORD prot = 0;
248*2ccfa855SEd Maste LONG s;
249*2ccfa855SEd Maste
250*2ccfa855SEd Maste memset(&req, 0, sizeof(req));
251*2ccfa855SEd Maste
252*2ccfa855SEd Maste if ((s = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
253*2ccfa855SEd Maste &ctx)) != SCARD_S_SUCCESS || ctx == 0) {
254*2ccfa855SEd Maste fido_log_debug("%s: SCardEstablishContext 0x%lx", __func__,
255*2ccfa855SEd Maste (long)s);
256*2ccfa855SEd Maste goto fail;
257*2ccfa855SEd Maste
258*2ccfa855SEd Maste }
259*2ccfa855SEd Maste if ((reader = get_reader(ctx, path)) == NULL) {
260*2ccfa855SEd Maste fido_log_debug("%s: get_reader(%s)", __func__, path);
261*2ccfa855SEd Maste goto fail;
262*2ccfa855SEd Maste }
263*2ccfa855SEd Maste if ((s = SCardConnect(ctx, reader, SCARD_SHARE_SHARED,
264*2ccfa855SEd Maste SCARD_PROTOCOL_Tx, &h, &prot)) != SCARD_S_SUCCESS) {
265*2ccfa855SEd Maste fido_log_debug("%s: SCardConnect 0x%lx", __func__, (long)s);
266*2ccfa855SEd Maste goto fail;
267*2ccfa855SEd Maste }
268*2ccfa855SEd Maste if (prepare_io_request(prot, &req) < 0) {
269*2ccfa855SEd Maste fido_log_debug("%s: prepare_io_request", __func__);
270*2ccfa855SEd Maste goto fail;
271*2ccfa855SEd Maste }
272*2ccfa855SEd Maste if ((dev = calloc(1, sizeof(*dev))) == NULL)
273*2ccfa855SEd Maste goto fail;
274*2ccfa855SEd Maste
275*2ccfa855SEd Maste dev->ctx = ctx;
276*2ccfa855SEd Maste dev->h = h;
277*2ccfa855SEd Maste dev->req = req;
278*2ccfa855SEd Maste ctx = 0;
279*2ccfa855SEd Maste h = 0;
280*2ccfa855SEd Maste fail:
281*2ccfa855SEd Maste if (h != 0)
282*2ccfa855SEd Maste SCardDisconnect(h, SCARD_LEAVE_CARD);
283*2ccfa855SEd Maste if (ctx != 0)
284*2ccfa855SEd Maste SCardReleaseContext(ctx);
285*2ccfa855SEd Maste free(reader);
286*2ccfa855SEd Maste
287*2ccfa855SEd Maste return dev;
288*2ccfa855SEd Maste }
289*2ccfa855SEd Maste
290*2ccfa855SEd Maste void
fido_pcsc_close(void * handle)291*2ccfa855SEd Maste fido_pcsc_close(void *handle)
292*2ccfa855SEd Maste {
293*2ccfa855SEd Maste struct pcsc *dev = handle;
294*2ccfa855SEd Maste
295*2ccfa855SEd Maste if (dev->h != 0)
296*2ccfa855SEd Maste SCardDisconnect(dev->h, SCARD_LEAVE_CARD);
297*2ccfa855SEd Maste if (dev->ctx != 0)
298*2ccfa855SEd Maste SCardReleaseContext(dev->ctx);
299*2ccfa855SEd Maste
300*2ccfa855SEd Maste explicit_bzero(dev->rx_buf, sizeof(dev->rx_buf));
301*2ccfa855SEd Maste free(dev);
302*2ccfa855SEd Maste }
303*2ccfa855SEd Maste
304*2ccfa855SEd Maste int
fido_pcsc_read(void * handle,unsigned char * buf,size_t len,int ms)305*2ccfa855SEd Maste fido_pcsc_read(void *handle, unsigned char *buf, size_t len, int ms)
306*2ccfa855SEd Maste {
307*2ccfa855SEd Maste struct pcsc *dev = handle;
308*2ccfa855SEd Maste int r;
309*2ccfa855SEd Maste
310*2ccfa855SEd Maste (void)ms;
311*2ccfa855SEd Maste if (dev->rx_len == 0 || dev->rx_len > len ||
312*2ccfa855SEd Maste dev->rx_len > sizeof(dev->rx_buf)) {
313*2ccfa855SEd Maste fido_log_debug("%s: rx_len", __func__);
314*2ccfa855SEd Maste return -1;
315*2ccfa855SEd Maste }
316*2ccfa855SEd Maste fido_log_xxd(dev->rx_buf, dev->rx_len, "%s: reading", __func__);
317*2ccfa855SEd Maste memcpy(buf, dev->rx_buf, dev->rx_len);
318*2ccfa855SEd Maste explicit_bzero(dev->rx_buf, sizeof(dev->rx_buf));
319*2ccfa855SEd Maste r = (int)dev->rx_len;
320*2ccfa855SEd Maste dev->rx_len = 0;
321*2ccfa855SEd Maste
322*2ccfa855SEd Maste return r;
323*2ccfa855SEd Maste }
324*2ccfa855SEd Maste
325*2ccfa855SEd Maste int
fido_pcsc_write(void * handle,const unsigned char * buf,size_t len)326*2ccfa855SEd Maste fido_pcsc_write(void *handle, const unsigned char *buf, size_t len)
327*2ccfa855SEd Maste {
328*2ccfa855SEd Maste struct pcsc *dev = handle;
329*2ccfa855SEd Maste DWORD n;
330*2ccfa855SEd Maste LONG s;
331*2ccfa855SEd Maste
332*2ccfa855SEd Maste if (len > INT_MAX) {
333*2ccfa855SEd Maste fido_log_debug("%s: len", __func__);
334*2ccfa855SEd Maste return -1;
335*2ccfa855SEd Maste }
336*2ccfa855SEd Maste
337*2ccfa855SEd Maste explicit_bzero(dev->rx_buf, sizeof(dev->rx_buf));
338*2ccfa855SEd Maste dev->rx_len = 0;
339*2ccfa855SEd Maste n = (DWORD)sizeof(dev->rx_buf);
340*2ccfa855SEd Maste
341*2ccfa855SEd Maste fido_log_xxd(buf, len, "%s: writing", __func__);
342*2ccfa855SEd Maste
343*2ccfa855SEd Maste if ((s = SCardTransmit(dev->h, &dev->req, buf, (DWORD)len, NULL,
344*2ccfa855SEd Maste dev->rx_buf, &n)) != SCARD_S_SUCCESS) {
345*2ccfa855SEd Maste fido_log_debug("%s: SCardTransmit 0x%lx", __func__, (long)s);
346*2ccfa855SEd Maste explicit_bzero(dev->rx_buf, sizeof(dev->rx_buf));
347*2ccfa855SEd Maste return -1;
348*2ccfa855SEd Maste }
349*2ccfa855SEd Maste dev->rx_len = (size_t)n;
350*2ccfa855SEd Maste
351*2ccfa855SEd Maste fido_log_xxd(dev->rx_buf, dev->rx_len, "%s: read", __func__);
352*2ccfa855SEd Maste
353*2ccfa855SEd Maste return (int)len;
354*2ccfa855SEd Maste }
355*2ccfa855SEd Maste
356*2ccfa855SEd Maste int
fido_pcsc_tx(fido_dev_t * d,uint8_t cmd,const u_char * buf,size_t count)357*2ccfa855SEd Maste fido_pcsc_tx(fido_dev_t *d, uint8_t cmd, const u_char *buf, size_t count)
358*2ccfa855SEd Maste {
359*2ccfa855SEd Maste return fido_nfc_tx(d, cmd, buf, count);
360*2ccfa855SEd Maste }
361*2ccfa855SEd Maste
362*2ccfa855SEd Maste int
fido_pcsc_rx(fido_dev_t * d,uint8_t cmd,u_char * buf,size_t count,int ms)363*2ccfa855SEd Maste fido_pcsc_rx(fido_dev_t *d, uint8_t cmd, u_char *buf, size_t count, int ms)
364*2ccfa855SEd Maste {
365*2ccfa855SEd Maste return fido_nfc_rx(d, cmd, buf, count, ms);
366*2ccfa855SEd Maste }
367*2ccfa855SEd Maste
368*2ccfa855SEd Maste bool
fido_is_pcsc(const char * path)369*2ccfa855SEd Maste fido_is_pcsc(const char *path)
370*2ccfa855SEd Maste {
371*2ccfa855SEd Maste return strncmp(path, FIDO_PCSC_PREFIX, strlen(FIDO_PCSC_PREFIX)) == 0;
372*2ccfa855SEd Maste }
373*2ccfa855SEd Maste
374*2ccfa855SEd Maste int
fido_dev_set_pcsc(fido_dev_t * d)375*2ccfa855SEd Maste fido_dev_set_pcsc(fido_dev_t *d)
376*2ccfa855SEd Maste {
377*2ccfa855SEd Maste if (d->io_handle != NULL) {
378*2ccfa855SEd Maste fido_log_debug("%s: device open", __func__);
379*2ccfa855SEd Maste return -1;
380*2ccfa855SEd Maste }
381*2ccfa855SEd Maste d->io_own = true;
382*2ccfa855SEd Maste d->io = (fido_dev_io_t) {
383*2ccfa855SEd Maste fido_pcsc_open,
384*2ccfa855SEd Maste fido_pcsc_close,
385*2ccfa855SEd Maste fido_pcsc_read,
386*2ccfa855SEd Maste fido_pcsc_write,
387*2ccfa855SEd Maste };
388*2ccfa855SEd Maste d->transport = (fido_dev_transport_t) {
389*2ccfa855SEd Maste fido_pcsc_rx,
390*2ccfa855SEd Maste fido_pcsc_tx,
391*2ccfa855SEd Maste };
392*2ccfa855SEd Maste
393*2ccfa855SEd Maste return 0;
394*2ccfa855SEd Maste }
395