1 | #ifdef HAVE_PCSC
|
---|
2 |
|
---|
3 | #include "ifd_pcsc.h"
|
---|
4 | int pcsc_reader_init(struct s_reader *pcsc_reader, char *device)
|
---|
5 | {
|
---|
6 | ULONG rv;
|
---|
7 | DWORD dwReaders;
|
---|
8 | LPSTR mszReaders = NULL;
|
---|
9 | char *ptr, **readers = NULL;
|
---|
10 | int nbReaders;
|
---|
11 | int reader_nb;
|
---|
12 |
|
---|
13 | pcsc_reader->pcsc_has_card=0;
|
---|
14 | pcsc_reader->hCard=0;
|
---|
15 | pcsc_reader->hContext=0;
|
---|
16 |
|
---|
17 | cs_debug("PCSC establish context for PCSC reader %s", device);
|
---|
18 | rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &pcsc_reader->hContext);
|
---|
19 | if ( rv == SCARD_S_SUCCESS ) {
|
---|
20 | // here we need to list the pcsc readers and get the name from there,
|
---|
21 | // the pcsc_reader->device should contain the reader number
|
---|
22 | // and after the actual device name is copied in pcsc_reader->pcsc_name .
|
---|
23 | rv = SCardListReaders(pcsc_reader->hContext, NULL, NULL, &dwReaders);
|
---|
24 | if( rv != SCARD_S_SUCCESS ) {
|
---|
25 | cs_debug("PCSC failed listing readers [1] : (%lx)", rv);
|
---|
26 | return 2;
|
---|
27 | }
|
---|
28 | mszReaders = malloc(sizeof(char)*dwReaders);
|
---|
29 | if (mszReaders == NULL) {
|
---|
30 | cs_debug("PCSC failed malloc");
|
---|
31 | return 2;
|
---|
32 | }
|
---|
33 | rv = SCardListReaders(pcsc_reader->hContext, NULL, mszReaders, &dwReaders);
|
---|
34 | if( rv != SCARD_S_SUCCESS ) {
|
---|
35 | cs_debug("PCSC failed listing readers [2]: (%lx)", rv);
|
---|
36 | free(mszReaders);
|
---|
37 | return 2;
|
---|
38 | }
|
---|
39 | /* Extract readers from the null separated string and get the total
|
---|
40 | * number of readers
|
---|
41 | */
|
---|
42 | nbReaders = 0;
|
---|
43 | ptr = mszReaders;
|
---|
44 | while (*ptr != '\0') {
|
---|
45 | ptr += strlen(ptr)+1;
|
---|
46 | nbReaders++;
|
---|
47 | }
|
---|
48 |
|
---|
49 | if (nbReaders == 0) {
|
---|
50 | cs_log("PCSC : no reader found");
|
---|
51 | free(mszReaders);
|
---|
52 | return 2;
|
---|
53 | }
|
---|
54 |
|
---|
55 | readers = calloc(nbReaders, sizeof(char *));
|
---|
56 | if (readers == NULL) {
|
---|
57 | cs_log("PCSC failed calloc");
|
---|
58 | return 2;
|
---|
59 | }
|
---|
60 |
|
---|
61 | /* fill the readers table */
|
---|
62 | nbReaders = 0;
|
---|
63 | ptr = mszReaders;
|
---|
64 | while (*ptr != '\0') {
|
---|
65 | cs_debug("PCSC reader %d: %s", nbReaders, ptr);
|
---|
66 | readers[nbReaders] = ptr;
|
---|
67 | ptr += strlen(ptr)+1;
|
---|
68 | nbReaders++;
|
---|
69 | }
|
---|
70 |
|
---|
71 | reader_nb=atoi((const char *)&pcsc_reader->device);
|
---|
72 | if (reader_nb < 0 || reader_nb >= nbReaders) {
|
---|
73 | cs_log("Wrong reader index: %d", reader_nb);
|
---|
74 | free(mszReaders);
|
---|
75 | free(readers);
|
---|
76 | return 2;
|
---|
77 | }
|
---|
78 |
|
---|
79 | snprintf(pcsc_reader->pcsc_name,sizeof(pcsc_reader->pcsc_name),"%s",readers[reader_nb]);
|
---|
80 | free(mszReaders);
|
---|
81 | free(readers);
|
---|
82 | }
|
---|
83 | else {
|
---|
84 | cs_log("PCSC failed establish context (%lx)", rv);
|
---|
85 | return 2;
|
---|
86 | }
|
---|
87 | return 0;
|
---|
88 | }
|
---|
89 |
|
---|
90 | int pcsc_reader_do_api(struct s_reader *pcsc_reader, const uchar *buf, uchar *cta_res, ushort *cta_lr, int l)
|
---|
91 | {
|
---|
92 | LONG rv;
|
---|
93 | SCARD_IO_REQUEST pioRecvPci;
|
---|
94 | DWORD dwSendLength, dwRecvLength;
|
---|
95 |
|
---|
96 | if(!l) {
|
---|
97 | cs_log("ERROR : data length to be send to the reader is %d" , l);
|
---|
98 | return ERR_INVALID;
|
---|
99 | }
|
---|
100 |
|
---|
101 | dwRecvLength = CTA_RES_LEN;
|
---|
102 | *cta_lr = 0;
|
---|
103 |
|
---|
104 | if(pcsc_reader->dwActiveProtocol == SCARD_PROTOCOL_T0) {
|
---|
105 | // explanantion as to why we do the test on buf[4] :
|
---|
106 | // Issuing a command without exchanging data :
|
---|
107 | //To issue a command to the card that does not involve the exchange of data (either sent or received), the send and receive buffers must be formatted as follows.
|
---|
108 | //The pbSendBuffer buffer must contain the CLA, INS, P1, and P2 values for the T=0 operation. The P3 value is not sent. (This is to differentiate the header from the case where 256 bytes are expected to be returned.)
|
---|
109 | //The cbSendLength parameter must be set to four, the size of the T=0 header information (CLA, INS, P1, and P2).
|
---|
110 | //The pbRecvBuffer will receive the SW1 and SW2 status codes from the operation.
|
---|
111 | //The pcbRecvLength should be at least two and will be set to two upon return.
|
---|
112 | if(buf[4])
|
---|
113 | dwSendLength = l;
|
---|
114 | else
|
---|
115 | dwSendLength = l-1;
|
---|
116 | cs_debug("sending %d bytes to PCSC : %s", dwSendLength,cs_hexdump(1,buf,l));
|
---|
117 | rv = SCardTransmit((SCARDHANDLE)(pcsc_reader->hCard), SCARD_PCI_T0, (LPCBYTE) buf, dwSendLength, &pioRecvPci, (LPBYTE) cta_res, (LPDWORD) &dwRecvLength);
|
---|
118 | *cta_lr=dwRecvLength;
|
---|
119 | }
|
---|
120 | else if(pcsc_reader->dwActiveProtocol == SCARD_PROTOCOL_T1) {
|
---|
121 | dwSendLength = l;
|
---|
122 | cs_debug("sending %d bytes to PCSC : %s", dwSendLength,cs_hexdump(1,buf,l));
|
---|
123 | rv = SCardTransmit((SCARDHANDLE)(pcsc_reader->hCard), SCARD_PCI_T1, (LPCBYTE) buf, dwSendLength, &pioRecvPci, (LPBYTE) cta_res, (LPDWORD) &dwRecvLength);
|
---|
124 | *cta_lr=dwRecvLength;
|
---|
125 | }
|
---|
126 | else {
|
---|
127 | cs_debug("PCSC invalid protocol (T=%d)", pcsc_reader->dwActiveProtocol);
|
---|
128 | return ERR_INVALID;
|
---|
129 | }
|
---|
130 |
|
---|
131 | cs_debug("received %d bytes from PCSC with rv=%lx : %s", *cta_lr, rv,cs_hexdump(1,cta_res,*cta_lr));
|
---|
132 |
|
---|
133 | cs_debug("PCSC doapi (%lx ) (T=%d), %d", rv, ( pcsc_reader->dwActiveProtocol == SCARD_PROTOCOL_T0 ? 0 : 1), *cta_lr );
|
---|
134 |
|
---|
135 | if ( rv == SCARD_S_SUCCESS ){
|
---|
136 | return OK;
|
---|
137 | }
|
---|
138 | else {
|
---|
139 | return ERR_INVALID;
|
---|
140 | }
|
---|
141 |
|
---|
142 | }
|
---|
143 |
|
---|
144 | int pcsc_activate_card(struct s_reader *pcsc_reader, uchar *atr, ushort *atr_size)
|
---|
145 | {
|
---|
146 | LONG rv;
|
---|
147 | DWORD dwState, dwAtrLen, dwReaderLen;
|
---|
148 | BYTE pbAtr[64];
|
---|
149 |
|
---|
150 | cs_debug("PCSC initializing card in (%s)", pcsc_reader->pcsc_name);
|
---|
151 | dwAtrLen = sizeof(pbAtr);
|
---|
152 | dwReaderLen=0;
|
---|
153 |
|
---|
154 | cs_debug("PCSC resetting card in (%s) with handle %lu", pcsc_reader->pcsc_name,(SCARDHANDLE)(pcsc_reader->hCard));
|
---|
155 | rv = SCardReconnect((SCARDHANDLE)(pcsc_reader->hCard), SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_RESET_CARD, &pcsc_reader->dwActiveProtocol);
|
---|
156 |
|
---|
157 | if ( rv != SCARD_S_SUCCESS ) {
|
---|
158 | cs_debug("Error PCSC failed to reset card (%lx)", rv);
|
---|
159 | return(0);
|
---|
160 | }
|
---|
161 |
|
---|
162 | cs_debug("PCSC resetting done on card in (%s)", pcsc_reader->pcsc_name);
|
---|
163 | cs_debug("PCSC Protocol (T=%d)",( pcsc_reader->dwActiveProtocol == SCARD_PROTOCOL_T0 ? 0 : 1));
|
---|
164 |
|
---|
165 | cs_debug("PCSC getting ATR for card in (%s)", pcsc_reader->pcsc_name);
|
---|
166 | rv = SCardStatus((SCARDHANDLE)(pcsc_reader->hCard),NULL, &dwReaderLen, &dwState, &pcsc_reader->dwActiveProtocol, pbAtr, &dwAtrLen);
|
---|
167 | if ( rv == SCARD_S_SUCCESS ) {
|
---|
168 | cs_debug("PCSC Protocol (T=%d)",( pcsc_reader->dwActiveProtocol == SCARD_PROTOCOL_T0 ? 0 : 1));
|
---|
169 | memcpy(atr, pbAtr, dwAtrLen);
|
---|
170 | *atr_size=dwAtrLen;
|
---|
171 | pcsc_reader->init_history_pos=0;
|
---|
172 |
|
---|
173 | cs_log("%s ATR: %s",pcsc_reader->label, cs_hexdump(1, (uchar *)pbAtr, dwAtrLen));
|
---|
174 | return(1);
|
---|
175 | }
|
---|
176 | else {
|
---|
177 | cs_debug("Error PCSC failed to get ATR for card (%lx)", rv);
|
---|
178 | }
|
---|
179 |
|
---|
180 | return(0);
|
---|
181 | }
|
---|
182 |
|
---|
183 |
|
---|
184 | int pcsc_check_card_inserted(struct s_reader *pcsc_reader)
|
---|
185 | {
|
---|
186 | DWORD dwState, dwAtrLen, dwReaderLen;
|
---|
187 | BYTE pbAtr[64];
|
---|
188 | LONG rv;
|
---|
189 |
|
---|
190 | dwAtrLen = sizeof(pbAtr);
|
---|
191 | rv=0;
|
---|
192 | dwState=0;
|
---|
193 | dwReaderLen=0;
|
---|
194 |
|
---|
195 | // Do we have a card ?
|
---|
196 | if (!pcsc_reader->pcsc_has_card && !(SCARDHANDLE)(pcsc_reader->hCard)) {
|
---|
197 | // try connecting to the card
|
---|
198 | rv = SCardConnect(pcsc_reader->hContext, pcsc_reader->pcsc_name, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &pcsc_reader->hCard, &pcsc_reader->dwActiveProtocol);
|
---|
199 | if (rv==SCARD_E_NO_SMARTCARD) {
|
---|
200 | // no card in reader
|
---|
201 | pcsc_reader->pcsc_has_card=0;
|
---|
202 | if((SCARDHANDLE)(pcsc_reader->hCard)) {
|
---|
203 | SCardDisconnect((SCARDHANDLE)(pcsc_reader->hCard),SCARD_RESET_CARD);
|
---|
204 | pcsc_reader->hCard=0;
|
---|
205 | }
|
---|
206 | // cs_debug("PCSC card in %s removed / absent [dwstate=%lx rv=(%lx)]", pcsc_reader->pcsc_name, dwState, rv );
|
---|
207 | return 0;
|
---|
208 | }
|
---|
209 | else if( rv == SCARD_W_UNRESPONSIVE_CARD ) {
|
---|
210 | // there is a problem with the card in the reader
|
---|
211 | pcsc_reader->pcsc_has_card=0;
|
---|
212 | pcsc_reader->hCard=0;
|
---|
213 | cs_log("PCSC card in %s is unresponsive. Eject and re-insert please.", pcsc_reader->pcsc_name);
|
---|
214 | return 0;
|
---|
215 | }
|
---|
216 | else if( rv == SCARD_S_SUCCESS ) {
|
---|
217 | // we have a card
|
---|
218 | pcsc_reader->pcsc_has_card=1;
|
---|
219 | }
|
---|
220 | else {
|
---|
221 | // if we get here we have a bigger problem -> display status and debug
|
---|
222 | // cs_debug("PCSC reader %s status [dwstate=%lx rv=(%lx)]", pcsc_reader->pcsc_name, dwState, rv );
|
---|
223 | return 0;
|
---|
224 | }
|
---|
225 |
|
---|
226 | }
|
---|
227 |
|
---|
228 | // if we get there the card is ready, check its status
|
---|
229 | rv = SCardStatus((SCARDHANDLE)(pcsc_reader->hCard), NULL, &dwReaderLen, &dwState, &pcsc_reader->dwActiveProtocol, pbAtr, &dwAtrLen);
|
---|
230 |
|
---|
231 | if (rv == SCARD_S_SUCCESS && (dwState & (SCARD_PRESENT | SCARD_NEGOTIABLE | SCARD_POWERED ) )) {
|
---|
232 | return CARD_INSERTED;
|
---|
233 | }
|
---|
234 | else {
|
---|
235 | SCardDisconnect((SCARDHANDLE)(pcsc_reader->hCard),SCARD_RESET_CARD);
|
---|
236 | pcsc_reader->hCard=0;
|
---|
237 | pcsc_reader->pcsc_has_card=0;
|
---|
238 | }
|
---|
239 |
|
---|
240 | return 0;
|
---|
241 | }
|
---|
242 |
|
---|
243 | void pcsc_close(struct s_reader *pcsc_reader)
|
---|
244 | {
|
---|
245 | cs_debug_mask (D_IFD, "PCSC : Closing device %s", pcsc_reader->device);
|
---|
246 | SCardDisconnect((SCARDHANDLE)(pcsc_reader->hCard),SCARD_RESET_CARD);
|
---|
247 | SCardReleaseContext(pcsc_reader->hContext);
|
---|
248 | pcsc_reader->hCard=0;
|
---|
249 | pcsc_reader->pcsc_has_card=0;
|
---|
250 | }
|
---|
251 | #endif
|
---|
252 |
|
---|