source: trunk/reader-pcsc.c@ 1008

Last change on this file since 1008 was 1008, 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 rv = SCardTransmit(pcsc_reader->hCard, SCARD_PCI_T1, buf, dwSendLength, &pioRecvPci, cta_res, &dwRecvLength);
107 }
108 else {
109 cs_debug("PCSC invalid protocol (T=%d)", pcsc_reader->dwActiveProtocol);
110 return ERR_INVALID;
111 }
112
113 *cta_lr=dwRecvLength;
114 cs_debug("received %d bytes from PCSC with rv=%lx", *cta_lr, rv);
115
116 cs_debug("PCSC doapi (%lx ) (T=%d), %d", rv, ( pcsc_reader->dwActiveProtocol == SCARD_PROTOCOL_T0 ? 0 : 1), dwRecvLength );
117 if ( rv == SCARD_S_SUCCESS ){
118 return OK;
119 }
120 else {
121 return ERR_INVALID;
122 }
123
124}
125
126int pcsc_activate_card(struct s_reader *pcsc_reader, uchar *atr, ushort *atr_size)
127{
128 ULONG rv;
129 DWORD dwState, dwAtrLen, dwReaderLen;
130 BYTE pbAtr[64];
131
132 cs_debug("PCSC initializing card in (%s)", pcsc_reader->pcsc_name);
133 dwAtrLen = sizeof(pbAtr);
134 dwReaderLen=0;
135
136 cs_debug("PCSC resetting card in (%s)", pcsc_reader->pcsc_name);
137 rv = SCardReconnect(pcsc_reader->hCard, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_RESET_CARD, &pcsc_reader->dwActiveProtocol);
138 cs_debug("PCSC resetting done on card in (%s)", pcsc_reader->pcsc_name);
139 cs_debug("PCSC Protocol (T=%d)",( pcsc_reader->dwActiveProtocol == SCARD_PROTOCOL_T0 ? 0 : 1));
140
141 if ( rv != SCARD_S_SUCCESS ) {
142 cs_debug("Error PCSC failed to reset card (%lx)", rv);
143 return(0);
144 }
145
146
147 cs_debug("PCSC getting ATR for card in (%s)", pcsc_reader->pcsc_name);
148 rv = SCardStatus(pcsc_reader->hCard,NULL, &dwReaderLen, &dwState, &pcsc_reader->dwActiveProtocol, pbAtr, &dwAtrLen);
149 if ( rv == SCARD_S_SUCCESS ) {
150 cs_debug("PCSC Protocol (T=%d)",( pcsc_reader->dwActiveProtocol == SCARD_PROTOCOL_T0 ? 0 : 1));
151 memcpy(atr, pbAtr, dwAtrLen);
152 *atr_size=dwAtrLen;
153#ifdef CS_RDR_INIT_HIST
154 pcsc_reader->init_history_pos=0;
155 memset(pcsc_reader->init_history, 0, sizeof(pcsc_reader->init_history));
156#endif
157 cs_ri_log("ATR: %s", cs_hexdump(1, (uchar *)pbAtr, dwAtrLen));
158 return(1);
159 }
160 else {
161 cs_debug("Error PCSC failed to get ATR for card (%lx)", rv);
162 }
163
164 return(0);
165}
166
167
168int pcsc_check_card_inserted(struct s_reader *pcsc_reader)
169{
170 DWORD dwState, dwAtrLen, dwReaderLen;
171 BYTE pbAtr[64];
172 ULONG rv;
173
174 dwAtrLen = sizeof(pbAtr);
175 rv=0;
176 dwState=0;
177 dwReaderLen=0;
178
179 // Do we have a card ?
180 if (!pcsc_reader->pcsc_has_card && !pcsc_reader->hCard) {
181 // try connecting to the card
182 rv = SCardConnect(pcsc_reader->hContext, pcsc_reader->pcsc_name, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &pcsc_reader->hCard, &pcsc_reader->dwActiveProtocol);
183 if (rv==SCARD_E_NO_SMARTCARD) {
184 // no card in reader
185 pcsc_reader->pcsc_has_card=0;
186 if(pcsc_reader->hCard) {
187 SCardDisconnect(pcsc_reader->hCard,SCARD_RESET_CARD);
188 pcsc_reader->hCard=0;
189 }
190 cs_debug("PCSC card in %s removed / absent [dwstate=%lx rv=(%lx)]", pcsc_reader->pcsc_name, dwState, rv );
191 return 0;
192 }
193 else if( rv == SCARD_W_UNRESPONSIVE_CARD ) {
194 // there is a problem with the card in the reader
195 pcsc_reader->pcsc_has_card=0;
196 pcsc_reader->hCard=0;
197 cs_log("PCSC card in %s is unresponsive. Eject and re-insert please.", pcsc_reader->pcsc_name);
198 return 0;
199 }
200 else if( rv == SCARD_S_SUCCESS ) {
201 // we have a card
202 pcsc_reader->pcsc_has_card=1;
203 }
204 else {
205 // if we get here we have a bigger problem -> display status and debug
206 cs_debug("PCSC reader %s status [dwstate=%lx rv=(%lx)]", pcsc_reader->pcsc_name, dwState, rv );
207 return 0;
208 }
209
210 }
211
212 // if we get there the card is ready, check its status
213 rv = SCardStatus(pcsc_reader->hCard, NULL, &dwReaderLen, &dwState, &pcsc_reader->dwActiveProtocol, pbAtr, &dwAtrLen);
214
215 if (rv == SCARD_S_SUCCESS && (dwState & (SCARD_PRESENT | SCARD_NEGOTIABLE | SCARD_POWERED ) )) {
216 cs_debug("PCSC card IS inserted in %s card state [dwstate=%lx rv=(%lx)]", pcsc_reader->pcsc_name, dwState,rv);
217 return CARD_INSERTED;
218 }
219 else {
220 SCardDisconnect(pcsc_reader->hCard,SCARD_RESET_CARD);
221 pcsc_reader->hCard=0;
222 pcsc_reader->pcsc_has_card=0;
223 cs_debug("PCSC card in %s removed / absent [dwstate=%lx rv=(%lx)]", pcsc_reader->pcsc_name, dwState, rv );
224 }
225
226 return 0;
227}
228#endif
229
Note: See TracBrowser for help on using the repository browser.