source: trunk/reader-pcsc.c@ 1009

Last change on this file since 1009 was 1009, checked in by rorothetroll, 13 years ago

added a comment with the explanation for the PCSC issue

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