xref: /freebsd/contrib/libfido2/src/pcsc.c (revision 2ccfa855)
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