1
/* pcsc-wrapper.c - Wrapper for ccessing the PC/SC service
2
* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
4
* This file is part of GnuPG.
6
* GnuPG is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* GnuPG is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
22
This wrapper is required to handle problems with the libpscslite
23
library. That library assumes that pthreads are used and fails
24
badly if one tries to use it with a procerss using Pth.
26
The operation model is pretty simple: It reads requests from stdin
27
and returns the answer on stdout. There is no direct mapping to the
28
pcsc interface but to a higher level one which resembles the code
29
used in scdaemon (apdu.c) when not using Pth or while running under
32
The interface is binary consisting of a command tag and the length
33
of the parameter list. The calling process needs to pass the
34
version number of the interface on the command line to make sure
35
that both agree on the same interface. For each port a separate
36
instance of this process needs to be started.
53
#define PGM "pcsc-wrapper"
55
/* Allow for a standalone build. */
57
#define MYVERSION_LINE PGM " (GnuPG) " VERSION
58
#define BUGREPORT_LINE "\nReport bugs to <bug-gnupg@gnu.org>.\n"
60
#define MYVERSION_LINE PGM
61
#define BUGREPORT_LINE ""
64
#define DEFAULT_PCSC_DRIVER "libpcsclite.so"
70
/* PC/SC constants and function pointer. */
71
#define PCSC_SCOPE_USER 0
72
#define PCSC_SCOPE_TERMINAL 1
73
#define PCSC_SCOPE_SYSTEM 2
74
#define PCSC_SCOPE_GLOBAL 3
76
#define PCSC_PROTOCOL_T0 1
77
#define PCSC_PROTOCOL_T1 2
78
#define PCSC_PROTOCOL_RAW 4
80
#define PCSC_SHARE_EXCLUSIVE 1
81
#define PCSC_SHARE_SHARED 2
82
#define PCSC_SHARE_DIRECT 3
84
#define PCSC_LEAVE_CARD 0
85
#define PCSC_RESET_CARD 1
86
#define PCSC_UNPOWER_CARD 2
87
#define PCSC_EJECT_CARD 3
89
#define PCSC_UNKNOWN 0x0001
90
#define PCSC_ABSENT 0x0002 /* Card is absent. */
91
#define PCSC_PRESENT 0x0004 /* Card is present. */
92
#define PCSC_SWALLOWED 0x0008 /* Card is present and electrical connected. */
93
#define PCSC_POWERED 0x0010 /* Card is powered. */
94
#define PCSC_NEGOTIABLE 0x0020 /* Card is awaiting PTS. */
95
#define PCSC_SPECIFIC 0x0040 /* Card is ready for use. */
97
#define PCSC_STATE_UNAWARE 0x0000 /* Want status. */
98
#define PCSC_STATE_IGNORE 0x0001 /* Ignore this reader. */
99
#define PCSC_STATE_CHANGED 0x0002 /* State has changed. */
100
#define PCSC_STATE_UNKNOWN 0x0004 /* Reader unknown. */
101
#define PCSC_STATE_UNAVAILABLE 0x0008 /* Status unavailable. */
102
#define PCSC_STATE_EMPTY 0x0010 /* Card removed. */
103
#define PCSC_STATE_PRESENT 0x0020 /* Card inserted. */
104
#define PCSC_STATE_ATRMATCH 0x0040 /* ATR matches card. */
105
#define PCSC_STATE_EXCLUSIVE 0x0080 /* Exclusive Mode. */
106
#define PCSC_STATE_INUSE 0x0100 /* Shared mode. */
107
#define PCSC_STATE_MUTE 0x0200 /* Unresponsive card. */
109
struct pcsc_io_request_s {
110
unsigned long protocol;
111
unsigned long pci_len;
114
typedef struct pcsc_io_request_s *pcsc_io_request_t;
116
struct pcsc_readerstate_s
120
unsigned long current_state;
121
unsigned long event_state;
122
unsigned long atrlen;
123
unsigned char atr[33];
126
typedef struct pcsc_readerstate_s *pcsc_readerstate_t;
129
static int driver_is_open; /* True if the PC/SC driver has been
130
initialzied and is ready for
131
operations. The following variables
133
static unsigned long pcsc_context; /* The current PC/CS context. */
134
static char *current_rdrname;
135
static unsigned long pcsc_card;
136
static unsigned long pcsc_protocol;
137
static unsigned char current_atr[33];
138
static size_t current_atrlen;
140
long (* pcsc_establish_context) (unsigned long scope,
141
const void *reserved1,
142
const void *reserved2,
143
unsigned long *r_context);
144
long (* pcsc_release_context) (unsigned long context);
145
long (* pcsc_list_readers) (unsigned long context,
147
char *readers, unsigned long*readerslen);
148
long (* pcsc_get_status_change) (unsigned long context,
149
unsigned long timeout,
150
pcsc_readerstate_t readerstates,
151
unsigned long nreaderstates);
152
long (* pcsc_connect) (unsigned long context,
154
unsigned long share_mode,
155
unsigned long preferred_protocols,
156
unsigned long *r_card,
157
unsigned long *r_active_protocol);
158
long (* pcsc_reconnect) (unsigned long card,
159
unsigned long share_mode,
160
unsigned long preferred_protocols,
161
unsigned long initialization,
162
unsigned long *r_active_protocol);
163
long (* pcsc_disconnect) (unsigned long card,
164
unsigned long disposition);
165
long (* pcsc_status) (unsigned long card,
166
char *reader, unsigned long *readerlen,
167
unsigned long *r_state,
168
unsigned long *r_protocol,
169
unsigned char *atr, unsigned long *atrlen);
170
long (* pcsc_begin_transaction) (unsigned long card);
171
long (* pcsc_end_transaction) (unsigned long card);
172
long (* pcsc_transmit) (unsigned long card,
173
const pcsc_io_request_t send_pci,
174
const unsigned char *send_buffer,
175
unsigned long send_len,
176
pcsc_io_request_t recv_pci,
177
unsigned char *recv_buffer,
178
unsigned long *recv_len);
179
long (* pcsc_set_timeout) (unsigned long context,
180
unsigned long timeout);
185
bad_request (const char *type)
187
fprintf (stderr, PGM ": bad `%s' request\n", type);
192
request_failed (int err)
197
putchar (0x81); /* Simple error/success response. */
204
putchar ((err >> 24) & 0xff);
205
putchar ((err >> 16) & 0xff);
206
putchar ((err >> 8) & 0xff);
207
putchar ((err ) & 0xff);
214
request_succeeded (const void *buffer, size_t buflen)
218
putchar (0x81); /* Simple error/success response. */
221
putchar ((len >> 24) & 0xff);
222
putchar ((len >> 16) & 0xff);
223
putchar ((len >> 8) & 0xff);
224
putchar ((len ) & 0xff);
232
/* Optional reponse string. */
234
fwrite (buffer, buflen, 1, stdout);
250
if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
252
fprintf (stderr, PGM ": premature EOF while parsing request\n");
255
return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4;
261
pcsc_error_string (long err)
267
if ((err & 0x80100000) != 0x80100000)
268
return "invalid PC/SC error code";
272
case 0x0002: s = "cancelled"; break;
273
case 0x000e: s = "can't dispose"; break;
274
case 0x0008: s = "insufficient buffer"; break;
275
case 0x0015: s = "invalid ATR"; break;
276
case 0x0003: s = "invalid handle"; break;
277
case 0x0004: s = "invalid parameter"; break;
278
case 0x0005: s = "invalid target"; break;
279
case 0x0011: s = "invalid value"; break;
280
case 0x0006: s = "no memory"; break;
281
case 0x0013: s = "comm error"; break;
282
case 0x0001: s = "internal error"; break;
283
case 0x0014: s = "unknown error"; break;
284
case 0x0007: s = "waited too long"; break;
285
case 0x0009: s = "unknown reader"; break;
286
case 0x000a: s = "timeout"; break;
287
case 0x000b: s = "sharing violation"; break;
288
case 0x000c: s = "no smartcard"; break;
289
case 0x000d: s = "unknown card"; break;
290
case 0x000f: s = "proto mismatch"; break;
291
case 0x0010: s = "not ready"; break;
292
case 0x0012: s = "system cancelled"; break;
293
case 0x0016: s = "not transacted"; break;
294
case 0x0017: s = "reader unavailable"; break;
295
case 0x0065: s = "unsupported card"; break;
296
case 0x0066: s = "unresponsive card"; break;
297
case 0x0067: s = "unpowered card"; break;
298
case 0x0068: s = "reset card"; break;
299
case 0x0069: s = "removed card"; break;
300
case 0x006a: s = "inserted card"; break;
301
case 0x001f: s = "unsupported feature"; break;
302
case 0x0019: s = "PCI too small"; break;
303
case 0x001a: s = "reader unsupported"; break;
304
case 0x001b: s = "duplicate reader"; break;
305
case 0x001c: s = "card unsupported"; break;
306
case 0x001d: s = "no service"; break;
307
case 0x001e: s = "service stopped"; break;
308
default: s = "unknown PC/SC error code"; break;
314
load_pcsc_driver (const char *libname)
318
handle = dlopen (libname, RTLD_LAZY);
321
fprintf (stderr, PGM ": failed to open driver `%s': %s",
322
libname, dlerror ());
326
pcsc_establish_context = dlsym (handle, "SCardEstablishContext");
327
pcsc_release_context = dlsym (handle, "SCardReleaseContext");
328
pcsc_list_readers = dlsym (handle, "SCardListReaders");
329
pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange");
330
pcsc_connect = dlsym (handle, "SCardConnect");
331
pcsc_reconnect = dlsym (handle, "SCardReconnect");
332
pcsc_disconnect = dlsym (handle, "SCardDisconnect");
333
pcsc_status = dlsym (handle, "SCardStatus");
334
pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction");
335
pcsc_end_transaction = dlsym (handle, "SCardEndTransaction");
336
pcsc_transmit = dlsym (handle, "SCardTransmit");
337
pcsc_set_timeout = dlsym (handle, "SCardSetTimeout");
339
if (!pcsc_establish_context
340
|| !pcsc_release_context
341
|| !pcsc_list_readers
342
|| !pcsc_get_status_change
347
|| !pcsc_begin_transaction
348
|| !pcsc_end_transaction
350
/* || !pcsc_set_timeout */)
352
/* Note that set_timeout is currently not used and also not
353
available under Windows. */
355
"apdu_open_reader: invalid PC/SC driver "
356
"(%d%d%d%d%d%d%d%d%d%d%d%d)\n",
357
!!pcsc_establish_context,
358
!!pcsc_release_context,
360
!!pcsc_get_status_change,
365
!!pcsc_begin_transaction,
366
!!pcsc_end_transaction,
368
!!pcsc_set_timeout );
377
/* Handle a open request. The argument is expected to be a string
378
with the port identification. ARGBUF is always guaranteed to be
379
terminted by a 0 which is not counted in ARGLEN. We may modifiy
382
handle_open (unsigned char *argbuf, size_t arglen)
385
const char * portstr;
387
unsigned long nreader, listlen, atrlen;
389
unsigned long card_state, card_protocol;
390
unsigned char atr[33];
392
/* Make sure there is only the port string */
393
if (arglen != strlen (argbuf))
394
bad_request ("OPEN");
399
fprintf (stderr, PGM ": PC/SC has already been opened\n");
404
err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL, &pcsc_context);
407
fprintf (stderr, PGM": pcsc_establish_context failed: %s (0x%lx)\n",
408
pcsc_error_string (err), err);
409
request_failed (err);
413
err = pcsc_list_readers (pcsc_context, NULL, NULL, &nreader);
416
list = malloc (nreader+1); /* Better add 1 for safety reasons. */
419
fprintf (stderr, PGM": error allocating memory for reader list\n");
422
err = pcsc_list_readers (pcsc_context, NULL, list, &nreader);
426
fprintf (stderr, PGM": pcsc_list_readers failed: %s (0x%lx)\n",
427
pcsc_error_string (err), err);
428
pcsc_release_context (pcsc_context);
430
request_failed (err);
440
fprintf (stderr, PGM": detected reader `%s'\n", p);
441
if (nreader < (strlen (p)+1))
443
fprintf (stderr, PGM": invalid response from pcsc_list_readers\n");
446
nreader -= strlen (p)+1;
450
current_rdrname = malloc (strlen (portstr && *portstr? portstr:list)+1);
451
if (!current_rdrname)
453
fprintf (stderr, PGM": error allocating memory for reader name\n");
456
strcpy (current_rdrname, portstr && *portstr? portstr:list);
459
err = pcsc_connect (pcsc_context,
461
PCSC_SHARE_EXCLUSIVE,
462
PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
465
if (err == 0x8010000c) /* No smartcard. */
471
fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
472
pcsc_error_string (err), err);
473
pcsc_release_context (pcsc_context);
474
free (current_rdrname);
475
current_rdrname = NULL;
476
request_failed (err);
484
unsigned long readerlen;
487
readerlen = sizeof reader -1;
488
err = pcsc_status (pcsc_card,
490
&card_state, &card_protocol,
493
fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
494
pcsc_error_string (err), err);
497
if (atrlen >= sizeof atr || atrlen >= sizeof current_atr)
499
fprintf (stderr, PGM": ATR returned by pcsc_status"
503
memcpy (current_atr, atr, atrlen);
504
current_atrlen = atrlen;
509
request_succeeded (current_atr, current_atrlen);
514
/* Handle a close request. We expect no arguments. We may modifiy
517
handle_close (unsigned char *argbuf, size_t arglen)
521
fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
526
free (current_rdrname);
527
current_rdrname = NULL;
528
pcsc_release_context (pcsc_context);
530
request_succeeded (NULL, 0);
535
/* Handle a status request. We expect no arguments. We may modifiy
538
handle_status (unsigned char *argbuf, size_t arglen)
541
struct pcsc_readerstate_s rdrstates[1];
543
unsigned char buf[20];
547
fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
552
memset (rdrstates, 0, sizeof *rdrstates);
553
rdrstates[0].reader = current_rdrname;
554
rdrstates[0].current_state = PCSC_STATE_UNAWARE;
555
err = pcsc_get_status_change (pcsc_context,
558
if (err == 0x8010000a) /* Timeout. */
562
fprintf (stderr, PGM": pcsc_get_status_change failed: %s (0x%lx)\n",
563
pcsc_error_string (err), err);
564
request_failed (err);
569
if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) )
571
if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
573
/* We indicate a useful card if it is not in use by another
574
application. This is because we only use exclusive access
576
if ( (status & 6) == 6
577
&& !(rdrstates[0].event_state & PCSC_STATE_INUSE) )
580
/* First word is identical to the one used by apdu.c. */
585
/* The second word is the native PCSC state. */
586
buf[4] = (rdrstates[0].event_state >> 24);
587
buf[5] = (rdrstates[0].event_state >> 16);
588
buf[6] = (rdrstates[0].event_state >> 8);
589
buf[7] = (rdrstates[0].event_state >> 0);
591
request_succeeded (buf, 8);
595
/* Handle a reset request. We expect no arguments. We may modifiy
598
handle_reset (unsigned char *argbuf, size_t arglen)
602
unsigned long nreader, atrlen;
603
unsigned long card_state, card_protocol;
607
fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
614
err = pcsc_disconnect (pcsc_card, PCSC_LEAVE_CARD);
617
fprintf (stderr, PGM": pcsc_disconnect failed: %s (0x%lx)\n",
618
pcsc_error_string (err), err);
619
request_failed (err);
625
err = pcsc_connect (pcsc_context,
627
PCSC_SHARE_EXCLUSIVE,
628
PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
633
fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
634
pcsc_error_string (err), err);
636
request_failed (err);
642
nreader = sizeof reader - 1;
643
err = pcsc_status (pcsc_card,
645
&card_state, &card_protocol,
646
current_atr, &atrlen);
649
fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
650
pcsc_error_string (err), err);
652
request_failed (err);
656
request_succeeded (current_atr, current_atrlen);
661
/* Handle a transmit request. The argument is expected to be a buffer
662
with the APDU. We may modifiy ARGBUF. */
664
handle_transmit (unsigned char *argbuf, size_t arglen)
667
struct pcsc_io_request_s send_pci;
668
unsigned long recv_len;
669
unsigned char buffer[1024];
671
/* The apdu should at least be one byte. */
673
bad_request ("TRANSMIT");
677
fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
681
if ((pcsc_protocol & PCSC_PROTOCOL_T1))
682
send_pci.protocol = PCSC_PROTOCOL_T1;
684
send_pci.protocol = PCSC_PROTOCOL_T0;
685
send_pci.pci_len = sizeof send_pci;
686
recv_len = sizeof (buffer);
687
err = pcsc_transmit (pcsc_card, &send_pci, argbuf, arglen,
688
NULL, buffer, &recv_len);
692
fprintf (stderr, PGM": pcsc_transmit failed: %s (0x%lx)\n",
693
pcsc_error_string (err), err);
694
request_failed (err);
697
request_succeeded (buffer, recv_len);
703
print_version (int with_help)
705
fputs (MYVERSION_LINE "\n"
706
"Copyright (C) 2004 Free Software Foundation, Inc.\n"
707
"This program comes with ABSOLUTELY NO WARRANTY.\n"
708
"This is free software, and you are welcome to redistribute it\n"
709
"under certain conditions. See the file COPYING for details.\n",
714
"Usage: " PGM " [OPTIONS] API-NUMBER [LIBNAME]\n"
715
"Helper to connect scdaemon to the PC/SC library\n"
717
" --verbose enable extra informational output\n"
718
" --version print version of the program and exit\n"
719
" --help display this help and exit\n"
720
BUGREPORT_LINE, stdout );
727
main (int argc, char **argv)
737
while (argc && last_argc != argc )
740
if (!strcmp (*argv, "--"))
745
else if (!strcmp (*argv, "--version"))
747
else if (!strcmp (*argv, "--help"))
749
else if (!strcmp (*argv, "--verbose"))
755
if (argc != 1 && argc != 2)
757
fprintf (stderr, "usage: " PGM " API-NUMBER [LIBNAME]\n");
761
api_number = atoi (*argv);
765
fprintf (stderr, PGM ": api-number %d is not valid\n", api_number);
769
load_pcsc_driver (argc? *argv : DEFAULT_PCSC_DRIVER);
771
while ((c = getc (stdin)) != EOF)
774
unsigned char argbuffer[2048];
776
arglen = read_32 (stdin);
777
if (arglen >= sizeof argbuffer - 1)
779
fprintf (stderr, PGM ": request too long\n");
782
if (arglen && fread (argbuffer, arglen, 1, stdin) != 1)
784
fprintf (stderr, PGM ": error reading request: %s\n",
788
argbuffer[arglen] = 0;
792
handle_open (argbuffer, arglen);
796
handle_close (argbuffer, arglen);
801
handle_transmit (argbuffer, arglen);
805
handle_status (argbuffer, arglen);
809
handle_reset (argbuffer, arglen);
813
fprintf (stderr, PGM ": invalid request 0x%02X\n", c);
825
compile-command: "gcc -Wall -g -o pcsc-wrapper pcsc-wrapper.c -ldl"