1 /* pcsc-wrapper.c - Wrapper for accessing 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 3 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, see <http://www.gnu.org/licenses/>.
21 This wrapper is required to handle problems with the libpscslite
22 library. That library assumes that pthreads are used and fails
23 badly if one tries to use it with a procerss using Pth.
25 The operation model is pretty simple: It reads requests from stdin
26 and returns the answer on stdout. There is no direct mapping to the
27 pcsc interface but to a higher level one which resembles the code
28 used in scdaemon (apdu.c) when not using Pth or while running under
31 The interface is binary consisting of a command tag and the length
32 of the parameter list. The calling process needs to pass the
33 version number of the interface on the command line to make sure
34 that both agree on the same interface. For each port a separate
35 instance of this process needs to be started.
52 #define PGM "pcsc-wrapper"
54 /* Allow for a standalone build. */
56 #define MYVERSION_LINE PGM " (GnuPG) " VERSION
57 #define BUGREPORT_LINE "\nReport bugs to <bug-gnupg@gnu.org>.\n"
59 #define MYVERSION_LINE PGM
60 #define BUGREPORT_LINE ""
63 #define DEFAULT_PCSC_DRIVER "libpcsclite.so"
69 /* PC/SC constants and function pointer. */
70 #define PCSC_SCOPE_USER 0
71 #define PCSC_SCOPE_TERMINAL 1
72 #define PCSC_SCOPE_SYSTEM 2
73 #define PCSC_SCOPE_GLOBAL 3
75 #define PCSC_PROTOCOL_T0 1
76 #define PCSC_PROTOCOL_T1 2
77 #define PCSC_PROTOCOL_RAW 4
79 #define PCSC_SHARE_EXCLUSIVE 1
80 #define PCSC_SHARE_SHARED 2
81 #define PCSC_SHARE_DIRECT 3
83 #define PCSC_LEAVE_CARD 0
84 #define PCSC_RESET_CARD 1
85 #define PCSC_UNPOWER_CARD 2
86 #define PCSC_EJECT_CARD 3
88 #define PCSC_UNKNOWN 0x0001
89 #define PCSC_ABSENT 0x0002 /* Card is absent. */
90 #define PCSC_PRESENT 0x0004 /* Card is present. */
91 #define PCSC_SWALLOWED 0x0008 /* Card is present and electrical connected. */
92 #define PCSC_POWERED 0x0010 /* Card is powered. */
93 #define PCSC_NEGOTIABLE 0x0020 /* Card is awaiting PTS. */
94 #define PCSC_SPECIFIC 0x0040 /* Card is ready for use. */
96 #define PCSC_STATE_UNAWARE 0x0000 /* Want status. */
97 #define PCSC_STATE_IGNORE 0x0001 /* Ignore this reader. */
98 #define PCSC_STATE_CHANGED 0x0002 /* State has changed. */
99 #define PCSC_STATE_UNKNOWN 0x0004 /* Reader unknown. */
100 #define PCSC_STATE_UNAVAILABLE 0x0008 /* Status unavailable. */
101 #define PCSC_STATE_EMPTY 0x0010 /* Card removed. */
102 #define PCSC_STATE_PRESENT 0x0020 /* Card inserted. */
103 #define PCSC_STATE_ATRMATCH 0x0040 /* ATR matches card. */
104 #define PCSC_STATE_EXCLUSIVE 0x0080 /* Exclusive Mode. */
105 #define PCSC_STATE_INUSE 0x0100 /* Shared mode. */
106 #define PCSC_STATE_MUTE 0x0200 /* Unresponsive card. */
108 struct pcsc_io_request_s
{
109 unsigned long protocol
;
110 unsigned long pci_len
;
113 typedef struct pcsc_io_request_s
*pcsc_io_request_t
;
115 struct pcsc_readerstate_s
119 unsigned long current_state
;
120 unsigned long event_state
;
121 unsigned long atrlen
;
122 unsigned char atr
[33];
125 typedef struct pcsc_readerstate_s
*pcsc_readerstate_t
;
128 static int driver_is_open
; /* True if the PC/SC driver has been
129 initialzied and is ready for
130 operations. The following variables
132 static unsigned long pcsc_context
; /* The current PC/CS context. */
133 static char *current_rdrname
;
134 static unsigned long pcsc_card
;
135 static unsigned long pcsc_protocol
;
136 static unsigned char current_atr
[33];
137 static size_t current_atrlen
;
139 long (* pcsc_establish_context
) (unsigned long scope
,
140 const void *reserved1
,
141 const void *reserved2
,
142 unsigned long *r_context
);
143 long (* pcsc_release_context
) (unsigned long context
);
144 long (* pcsc_list_readers
) (unsigned long context
,
146 char *readers
, unsigned long*readerslen
);
147 long (* pcsc_get_status_change
) (unsigned long context
,
148 unsigned long timeout
,
149 pcsc_readerstate_t readerstates
,
150 unsigned long nreaderstates
);
151 long (* pcsc_connect
) (unsigned long context
,
153 unsigned long share_mode
,
154 unsigned long preferred_protocols
,
155 unsigned long *r_card
,
156 unsigned long *r_active_protocol
);
157 long (* pcsc_reconnect
) (unsigned long card
,
158 unsigned long share_mode
,
159 unsigned long preferred_protocols
,
160 unsigned long initialization
,
161 unsigned long *r_active_protocol
);
162 long (* pcsc_disconnect
) (unsigned long card
,
163 unsigned long disposition
);
164 long (* pcsc_status
) (unsigned long card
,
165 char *reader
, unsigned long *readerlen
,
166 unsigned long *r_state
,
167 unsigned long *r_protocol
,
168 unsigned char *atr
, unsigned long *atrlen
);
169 long (* pcsc_begin_transaction
) (unsigned long card
);
170 long (* pcsc_end_transaction
) (unsigned long card
,
171 unsigned long disposition
);
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 ((char*)argbuf
))
394 bad_request ("OPEN");
395 portstr
= (char*)argbuf
;
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
;
478 request_failed (err
);
486 unsigned long readerlen
;
489 readerlen
= sizeof reader
-1;
490 err
= pcsc_status (pcsc_card
,
492 &card_state
, &card_protocol
,
495 fprintf (stderr
, PGM
": pcsc_status failed: %s (0x%lx)\n",
496 pcsc_error_string (err
), err
);
499 if (atrlen
>= sizeof atr
|| atrlen
>= sizeof current_atr
)
501 fprintf (stderr
, PGM
": ATR returned by pcsc_status"
505 memcpy (current_atr
, atr
, atrlen
);
506 current_atrlen
= atrlen
;
511 request_succeeded (current_atr
, current_atrlen
);
516 /* Handle a close request. We expect no arguments. We may modifiy
519 handle_close (unsigned char *argbuf
, size_t arglen
)
523 fprintf (stderr
, PGM
": PC/SC has not yet been opened\n");
528 free (current_rdrname
);
529 current_rdrname
= NULL
;
530 pcsc_release_context (pcsc_context
);
534 request_succeeded (NULL
, 0);
539 /* Handle a status request. We expect no arguments. We may modifiy
542 handle_status (unsigned char *argbuf
, size_t arglen
)
545 struct pcsc_readerstate_s rdrstates
[1];
547 unsigned char buf
[20];
551 fprintf (stderr
, PGM
": PC/SC has not yet been opened\n");
556 memset (rdrstates
, 0, sizeof *rdrstates
);
557 rdrstates
[0].reader
= current_rdrname
;
558 rdrstates
[0].current_state
= PCSC_STATE_UNAWARE
;
559 err
= pcsc_get_status_change (pcsc_context
,
562 if (err
== 0x8010000a) /* Timeout. */
566 fprintf (stderr
, PGM
": pcsc_get_status_change failed: %s (0x%lx)\n",
567 pcsc_error_string (err
), err
);
568 request_failed (err
);
573 if ( !(rdrstates
[0].event_state
& PCSC_STATE_UNKNOWN
) )
575 if ( (rdrstates
[0].event_state
& PCSC_STATE_PRESENT
) )
577 if ( !(rdrstates
[0].event_state
& PCSC_STATE_MUTE
) )
579 /* We indicate a useful card if it is not in use by another
580 application. This is because we only use exclusive access
582 if ( (status
& 6) == 6
583 && !(rdrstates
[0].event_state
& PCSC_STATE_INUSE
) )
587 /* First word is identical to the one used by apdu.c. */
592 /* The second word is the native PCSC state. */
593 buf
[4] = (rdrstates
[0].event_state
>> 24);
594 buf
[5] = (rdrstates
[0].event_state
>> 16);
595 buf
[6] = (rdrstates
[0].event_state
>> 8);
596 buf
[7] = (rdrstates
[0].event_state
>> 0);
597 /* The third word is the protocol. */
598 buf
[8] = (pcsc_protocol
>> 24);
599 buf
[9] = (pcsc_protocol
>> 16);
600 buf
[10] = (pcsc_protocol
>> 8);
601 buf
[11] = (pcsc_protocol
);
603 request_succeeded (buf
, 8);
607 /* Handle a reset request. We expect no arguments. We may modifiy
610 handle_reset (unsigned char *argbuf
, size_t arglen
)
614 unsigned long nreader
, atrlen
;
615 unsigned long card_state
, card_protocol
;
619 fprintf (stderr
, PGM
": PC/SC has not yet been opened\n");
626 err
= pcsc_disconnect (pcsc_card
, PCSC_LEAVE_CARD
);
627 if (err
== 0x80100003) /* Invalid handle. (already disconnected) */
631 fprintf (stderr
, PGM
": pcsc_disconnect failed: %s (0x%lx)\n",
632 pcsc_error_string (err
), err
);
633 request_failed (err
);
639 err
= pcsc_connect (pcsc_context
,
641 PCSC_SHARE_EXCLUSIVE
,
642 PCSC_PROTOCOL_T0
|PCSC_PROTOCOL_T1
,
647 fprintf (stderr
, PGM
": pcsc_connect failed: %s (0x%lx)\n",
648 pcsc_error_string (err
), err
);
650 request_failed (err
);
656 nreader
= sizeof reader
- 1;
657 err
= pcsc_status (pcsc_card
,
659 &card_state
, &card_protocol
,
660 current_atr
, &atrlen
);
663 fprintf (stderr
, PGM
": pcsc_status failed: %s (0x%lx)\n",
664 pcsc_error_string (err
), err
);
666 request_failed (err
);
670 request_succeeded (current_atr
, current_atrlen
);
675 /* Handle a transmit request. The argument is expected to be a buffer
676 with the APDU. We may modifiy ARGBUF. */
678 handle_transmit (unsigned char *argbuf
, size_t arglen
)
681 struct pcsc_io_request_s send_pci
;
682 unsigned long recv_len
;
683 unsigned char buffer
[1024];
685 /* The apdu should at least be one byte. */
687 bad_request ("TRANSMIT");
691 fprintf (stderr
, PGM
": PC/SC has not yet been opened\n");
695 if ((pcsc_protocol
& PCSC_PROTOCOL_T1
))
696 send_pci
.protocol
= PCSC_PROTOCOL_T1
;
698 send_pci
.protocol
= PCSC_PROTOCOL_T0
;
699 send_pci
.pci_len
= sizeof send_pci
;
700 recv_len
= sizeof (buffer
);
701 err
= pcsc_transmit (pcsc_card
, &send_pci
, argbuf
, arglen
,
702 NULL
, buffer
, &recv_len
);
706 fprintf (stderr
, PGM
": pcsc_transmit failed: %s (0x%lx)\n",
707 pcsc_error_string (err
), err
);
708 request_failed (err
);
711 request_succeeded (buffer
, recv_len
);
717 print_version (int with_help
)
719 fputs (MYVERSION_LINE
"\n"
720 "Copyright (C) 2004 Free Software Foundation, Inc.\n"
721 "This program comes with ABSOLUTELY NO WARRANTY.\n"
722 "This is free software, and you are welcome to redistribute it\n"
723 "under certain conditions. See the file COPYING for details.\n",
728 "Usage: " PGM
" [OPTIONS] API-NUMBER [LIBNAME]\n"
729 "Helper to connect scdaemon to the PC/SC library\n"
731 " --verbose enable extra informational output\n"
732 " --version print version of the program and exit\n"
733 " --help display this help and exit\n"
734 BUGREPORT_LINE
, stdout
);
741 main (int argc
, char **argv
)
751 while (argc
&& last_argc
!= argc
)
754 if (!strcmp (*argv
, "--"))
759 else if (!strcmp (*argv
, "--version"))
761 else if (!strcmp (*argv
, "--help"))
763 else if (!strcmp (*argv
, "--verbose"))
769 if (argc
!= 1 && argc
!= 2)
771 fprintf (stderr
, "usage: " PGM
" API-NUMBER [LIBNAME]\n");
775 api_number
= atoi (*argv
);
779 fprintf (stderr
, PGM
": api-number %d is not valid\n", api_number
);
783 load_pcsc_driver (argc
? *argv
: DEFAULT_PCSC_DRIVER
);
785 while ((c
= getc (stdin
)) != EOF
)
788 unsigned char argbuffer
[2048];
790 arglen
= read_32 (stdin
);
791 if (arglen
>= sizeof argbuffer
- 1)
793 fprintf (stderr
, PGM
": request too long\n");
796 if (arglen
&& fread (argbuffer
, arglen
, 1, stdin
) != 1)
798 fprintf (stderr
, PGM
": error reading request: %s\n",
802 argbuffer
[arglen
] = 0;
806 handle_open (argbuffer
, arglen
);
810 handle_close (argbuffer
, arglen
);
815 handle_transmit (argbuffer
, arglen
);
819 handle_status (argbuffer
, arglen
);
823 handle_reset (argbuffer
, arglen
);
827 fprintf (stderr
, PGM
": invalid request 0x%02X\n", c
);
838 compile-command: "gcc -Wall -g -o pcsc-wrapper pcsc-wrapper.c -ldl"