/[pcsclite]/trunk/Drivers/ccid/examples/scardcontrol.c
ViewVC logotype

Contents of /trunk/Drivers/ccid/examples/scardcontrol.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1669 - (hide annotations) (download)
Tue Sep 20 07:05:04 2005 UTC (7 years, 8 months ago) by rousseau
File MIME type: text/plain
File size: 13901 byte(s)
use HOST_TO_CCID_16/HOST_TO_CCID_32
1 rousseau 889 /*
2     scardcontrol.c: sample code to use/test SCardControl() API
3     Copyright (C) 2004 Ludovic Rousseau
4    
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9    
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13     GNU General Public License for more details.
14    
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18     */
19    
20     /*
21     * $Id$
22     */
23    
24     #include <stdio.h>
25     #include <stdlib.h>
26 rousseau 1346 #include <sys/time.h>
27 rousseau 889 #include <unistd.h>
28     #include <string.h>
29 rousseau 972 #include <PCSC/winscard.h>
30 rousseau 1558 #include <PCSC/reader.h>
31 rousseau 889
32     #ifndef TRUE
33     #define TRUE 1
34     #define FALSE 0
35     #endif
36    
37     #define IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE SCARD_CTL_CODE(1)
38    
39     /* PCSC error message pretty print */
40     #define PCSC_ERROR_EXIT(rv, text) \
41     if (rv != SCARD_S_SUCCESS) \
42     { \
43     printf(text ": %s (0x%lX)\n", pcsc_stringify_error(rv), rv); \
44     goto end; \
45     } \
46     else \
47     printf(text ": OK\n\n");
48    
49     #define PCSC_ERROR_CONT(rv, text) \
50     if (rv != SCARD_S_SUCCESS) \
51     printf(text ": %s (0x%lX)\n", pcsc_stringify_error(rv), rv); \
52     else \
53     printf(text ": OK\n\n");
54    
55     int main(int argc, char *argv[])
56     {
57     LONG rv;
58     SCARDCONTEXT hContext;
59     DWORD dwReaders;
60 rousseau 972 LPTSTR mszReaders;
61 rousseau 889 char *ptr, **readers = NULL;
62     int nbReaders;
63     SCARDHANDLE hCard;
64     DWORD dwActiveProtocol, dwReaderLen, dwState, dwProt, dwAtrLen;
65     BYTE pbAtr[MAX_ATR_SIZE] = "";
66 rousseau 892 char pbReader[MAX_READERNAME] = "";
67 rousseau 889 int reader_nb;
68     int i, offset;
69     unsigned char bSendBuffer[MAX_BUFFER_SIZE];
70     unsigned char bRecvBuffer[MAX_BUFFER_SIZE];
71     DWORD length;
72 rousseau 1631 DWORD verify_ioctl = 0;
73     DWORD modify_ioctl = 0;
74 rousseau 972 SCARD_IO_REQUEST pioRecvPci;
75 rousseau 1635 SCARD_IO_REQUEST pioSendPci;
76 rousseau 1631 PCSC_TLV_STRUCTURE *pcsc_tlv;
77     PIN_VERIFY_STRUCTURE *pin_verify;
78     PIN_MODIFY_STRUCTURE *pin_modify;
79 rousseau 889
80     printf("SCardControl sample code\n");
81     printf("V 1.0 2004, Ludovic Rousseau <ludovic.rousseau@free.fr>\n");
82    
83 rousseau 1263 printf("\nTHIS PROGRAM IS NOT DESIGNED AS A TESTING TOOL!\n");
84     printf("Do NOT use it unless you really know what you do.\n\n");
85    
86 rousseau 889 rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
87     if (rv != SCARD_S_SUCCESS)
88     {
89     printf("SCardEstablishContext: Cannot Connect to Resource Manager %lX\n", rv);
90     return 1;
91     }
92    
93     /* Retrieve the available readers list */
94     rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
95     if (rv != SCARD_S_SUCCESS)
96     {
97     printf("SCardListReader: %lX\n", rv);
98     }
99    
100     mszReaders = malloc(sizeof(char)*dwReaders);
101     if (mszReaders == NULL)
102     {
103     printf("malloc: not enough memory\n");
104     goto end;
105     }
106    
107     rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
108     if (rv != SCARD_S_SUCCESS)
109     printf("SCardListReader: %lX\n", rv);
110    
111     /* Extract readers from the null separated string and get the total
112     * number of readers */
113     nbReaders = 0;
114     ptr = mszReaders;
115     while (*ptr != '\0')
116     {
117     ptr += strlen(ptr)+1;
118     nbReaders++;
119     }
120    
121     if (nbReaders == 0)
122     {
123     printf("No reader found\n");
124     goto end;
125     }
126    
127     /* allocate the readers table */
128     readers = calloc(nbReaders, sizeof(char *));
129     if (NULL == readers)
130     {
131     printf("Not enough memory for readers[]\n");
132     goto end;
133     }
134    
135     /* fill the readers table */
136     nbReaders = 0;
137     ptr = mszReaders;
138     while (*ptr != '\0')
139     {
140     printf("%d: %s\n", nbReaders, ptr);
141     readers[nbReaders] = ptr;
142     ptr += strlen(ptr)+1;
143     nbReaders++;
144     }
145    
146     if (argc > 1)
147     {
148     reader_nb = atoi(argv[1]);
149     if (reader_nb < 0 || reader_nb >= nbReaders)
150     {
151     printf("Wrong reader index: %d\n", reader_nb);
152     goto end;
153     }
154     }
155     else
156     reader_nb = 0;
157    
158 rousseau 900 /* connect to a reader (even without a card) */
159 rousseau 889 dwActiveProtocol = -1;
160     rv = SCardConnect(hContext, readers[reader_nb], SCARD_SHARE_DIRECT,
161 rousseau 940 SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
162 rousseau 889 printf(" Protocol: %ld\n", dwActiveProtocol);
163     PCSC_ERROR_EXIT(rv, "SCardConnect")
164    
165 rousseau 972 /* get GemPC firmware */
166     printf(" Get GemPC Firmware\n");
167 rousseau 889
168     /* this is specific to Gemplus readers */
169     bSendBuffer[0] = 0x02;
170     rv = SCardControl(hCard, IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE, bSendBuffer,
171     1, bRecvBuffer, sizeof(bRecvBuffer), &length);
172    
173     printf(" Firmware: ");
174     for (i=0; i<length; i++)
175     printf("%02X ", bRecvBuffer[i]);
176     printf("\n");
177    
178     bRecvBuffer[length] = '\0';
179     printf(" Firmware: %s (length %ld bytes)\n", bRecvBuffer, length);
180    
181     PCSC_ERROR_CONT(rv, "SCardControl")
182    
183     /* get card status */
184     dwAtrLen = sizeof(pbAtr);
185     dwReaderLen = sizeof(pbReader);
186     rv = SCardStatus(hCard, pbReader, &dwReaderLen, &dwState, &dwProt,
187     pbAtr, &dwAtrLen);
188     printf(" Reader: %s (length %ld bytes)\n", pbReader, dwReaderLen);
189     printf(" State: 0x%lX\n", dwState);
190     printf(" Prot: %ld\n", dwProt);
191     printf(" ATR (length %ld bytes):", dwAtrLen);
192     for (i=0; i<dwAtrLen; i++)
193     printf(" %02X", pbAtr[i]);
194     printf("\n");
195     PCSC_ERROR_CONT(rv, "SCardStatus")
196    
197 rousseau 900 /* does the reader support PIN verification? */
198 rousseau 1631 rv = SCardControl(hCard, CM_IOCTL_GET_FEATURE_REQUEST, NULL, 0,
199     bRecvBuffer, sizeof(bRecvBuffer), &length);
200    
201     printf(" TLV (%ld): ", length);
202     for (i=0; i<length; i++)
203     printf("%02X ", bRecvBuffer[i]);
204     printf("\n");
205    
206     PCSC_ERROR_CONT(rv, "SCardControl(CM_IOCTL_GET_FEATURE_REQUEST)")
207    
208     if (length % sizeof(PCSC_TLV_STRUCTURE))
209 rousseau 900 {
210 rousseau 1631 printf("Inconsistent result! Bad TLV values!\n");
211     goto end;
212     }
213    
214     /* get the number of elements instead of the complete size */
215     length /= sizeof(PCSC_TLV_STRUCTURE);
216    
217     pcsc_tlv = (PCSC_TLV_STRUCTURE *)bRecvBuffer;
218     for (i = 0; i < length; i++)
219     {
220     if (pcsc_tlv[i].tag == FEATURE_VERIFY_PIN_DIRECT)
221     verify_ioctl = pcsc_tlv[i].value;
222     if (pcsc_tlv[i].tag == FEATURE_MODIFY_PIN_DIRECT)
223     modify_ioctl = pcsc_tlv[i].value;
224     }
225    
226     if (0 == verify_ioctl)
227     {
228 rousseau 900 printf("Reader %s does not support PIN verification\n",
229     readers[reader_nb]);
230     goto end;
231     }
232    
233 rousseau 972 /* connect to a reader (even without a card) */
234     dwActiveProtocol = -1;
235     rv = SCardReconnect(hCard, SCARD_SHARE_SHARED,
236 rousseau 1635 SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1, SCARD_UNPOWER_CARD,
237     &dwActiveProtocol);
238 rousseau 972 printf(" Protocol: %ld\n", dwActiveProtocol);
239     PCSC_ERROR_EXIT(rv, "SCardReconnect")
240    
241 rousseau 1635 switch(dwActiveProtocol)
242     {
243     case SCARD_PROTOCOL_T0:
244     pioSendPci = *SCARD_PCI_T0;
245     break;
246     case SCARD_PROTOCOL_T1:
247     pioSendPci = *SCARD_PCI_T1;
248     break;
249     default:
250     printf("Unknown protocol\n");
251     return -1;
252     }
253    
254 rousseau 972 /* APDU select DF */
255     memcpy(bSendBuffer, "\x00\xA4\x04\x00\x05\x47\x54\x4F\x4B\x31", 10);
256     length = sizeof(bRecvBuffer);
257 rousseau 1635 rv = SCardTransmit(hCard, &pioSendPci, bSendBuffer, 10,
258 rousseau 972 &pioRecvPci, bRecvBuffer, &length);
259     printf(" card response:");
260     for (i=0; i<length; i++)
261     printf(" %02X", bRecvBuffer[i]);
262     printf("\n");
263     PCSC_ERROR_EXIT(rv, "SCardTransmit")
264    
265     /* APDU select EF */
266     memcpy(bSendBuffer, "\x00\xA4\x02\x00\x02\x00\x04", 7);
267     length = sizeof(bRecvBuffer);
268 rousseau 1635 rv = SCardTransmit(hCard, &pioSendPci, bSendBuffer, 7,
269 rousseau 972 &pioRecvPci, bRecvBuffer, &length);
270     printf(" card response:");
271     for (i=0; i<length; i++)
272     printf(" %02X", bRecvBuffer[i]);
273     printf("\n");
274     PCSC_ERROR_EXIT(rv, "SCardTransmit")
275    
276 rousseau 889 /* verify PIN */
277     printf(" Secure verify PIN\n");
278 rousseau 1631 pin_verify = (PIN_VERIFY_STRUCTURE *)bSendBuffer;
279    
280     /* PC/SC v2.0.2 Part 10 PIN verification data structure */
281     pin_verify -> bTimerOut = 0x00;
282     pin_verify -> bTimerOut2 = 0x00;
283     pin_verify -> bmFormatString = 0x82;
284     pin_verify -> bmPINBlockString = 0x04;
285     pin_verify -> bmPINLengthFormat = 0x00;
286 rousseau 1669 pin_verify -> wPINMaxExtraDigit = HOST_TO_CCID_16(0x0408); /* Min Max */
287 rousseau 1634 pin_verify -> bEntryValidationCondition = 0x02; /* validation key pressed */
288 rousseau 1631 pin_verify -> bNumberMessage = 0x00;
289 rousseau 1669 pin_verify -> wLangId = HOST_TO_CCID_16(0x0904);
290 rousseau 1631 pin_verify -> bMsgIndex = 0x00;
291     pin_verify -> bTeoPrologue[0] = 0x00;
292     pin_verify -> bTeoPrologue[1] = 0x00;
293     pin_verify -> bTeoPrologue[2] = 0x00;
294     /* pin_verify -> ulDataLength = 0x00; we don't know the size yet */
295    
296     /* APDU: 00 20 00 00 08 30 30 30 30 00 00 00 00 */
297 rousseau 889 offset = 0;
298 rousseau 1631 pin_verify -> abData[offset++] = 0x00; /* CLA */
299     pin_verify -> abData[offset++] = 0x20; /* INS: VERIFY */
300     pin_verify -> abData[offset++] = 0x00; /* P1 */
301     pin_verify -> abData[offset++] = 0x00; /* P2 */
302     pin_verify -> abData[offset++] = 0x08; /* Lc: 8 data bytes */
303     pin_verify -> abData[offset++] = 0x30; /* '0' */
304     pin_verify -> abData[offset++] = 0x30; /* '0' */
305     pin_verify -> abData[offset++] = 0x30; /* '0' */
306     pin_verify -> abData[offset++] = 0x30; /* '0' */
307     pin_verify -> abData[offset++] = 0x00; /* '\0' */
308     pin_verify -> abData[offset++] = 0x00; /* '\0' */
309     pin_verify -> abData[offset++] = 0x00; /* '\0' */
310     pin_verify -> abData[offset++] = 0x00; /* '\0' */
311 rousseau 1669 pin_verify -> ulDataLength = HOST_TO_CCID_32(offset); /* APDU size */
312 rousseau 889
313 rousseau 1631 length = sizeof(PIN_VERIFY_STRUCTURE) + offset -1; /* -1 because PIN_VERIFY_STRUCTURE contains the first byte of abData[] */
314 rousseau 889
315 rousseau 1631 printf(" command:");
316     for (i=0; i<length; i++)
317     printf(" %02X", bSendBuffer[i]);
318     printf("\n");
319     printf("Enter your PIN: ");
320     fflush(stdout);
321     rv = SCardControl(hCard, verify_ioctl, bSendBuffer,
322     length, bRecvBuffer, sizeof(bRecvBuffer), &length);
323    
324     printf(" card response:");
325     for (i=0; i<length; i++)
326     printf(" %02X", bRecvBuffer[i]);
327     printf("\n");
328     PCSC_ERROR_CONT(rv, "SCardControl")
329    
330     {
331     #ifndef S_SPLINT_S
332     fd_set fd;
333     #endif
334     struct timeval timeout;
335    
336     FD_ZERO(&fd);
337     FD_SET(STDIN_FILENO, &fd); /* stdin */
338     timeout.tv_sec = 0; /* timeout = 0 */
339     timeout.tv_usec = 0;
340    
341     /* we only try to read stdin if the pinpad is on a keyboard
342     * we do not read stdin for a SPR 532 for example */
343     if (select(1, &fd, NULL, NULL, &timeout) > 0)
344     {
345     /* read the fake digits */
346     char in[10]; /* 4 digits + \n + \0 */
347     (void)fgets(in, sizeof(in), stdin);
348    
349     printf("keyboard sent: %s", in);
350     }
351     }
352    
353     if (0 == modify_ioctl)
354     {
355     printf("Reader %s does not support PIN modification\n",
356     readers[reader_nb]);
357     goto end;
358     }
359    
360     /* Modify PIN */
361     printf(" Secure modify PIN\n");
362     pin_modify = (PIN_MODIFY_STRUCTURE *)bSendBuffer;
363    
364     /* PC/SC v2.0.2 Part 10 PIN verification data structure */
365     pin_modify -> bTimerOut = 0x00;
366     pin_modify -> bTimerOut2 = 0x00;
367     pin_modify -> bmFormatString = 0x82;
368     pin_modify -> bmPINBlockString = 0x04;
369     pin_modify -> bmPINLengthFormat = 0x00;
370 rousseau 1634 pin_modify -> bInsertionOffsetOld = 0x05; /* offset from APDU start */
371     pin_modify -> bInsertionOffsetNew = 0x0D; /* offset from APDU start */
372 rousseau 1669 pin_modify -> wPINMaxExtraDigit = HOST_TO_CCID_16(0x0408); /* Min Max */
373 rousseau 1634 pin_modify -> bConfirmPIN = 0x03; /* b0 set = confirmation requested */
374     /* b1 set = current PIN entry requested */
375     pin_modify -> bEntryValidationCondition = 0x02; /* validation key pressed */
376 rousseau 1631 pin_modify -> bNumberMessage = 0x00;
377 rousseau 1669 pin_modify -> wLangId = HOST_TO_CCID_16(0x0904);
378 rousseau 1631 pin_modify -> bMsgIndex1 = 0x00;
379     pin_modify -> bMsgIndex2 = 0x00;
380     pin_modify -> bMsgIndex3 = 0x00;
381     pin_modify -> bTeoPrologue[0] = 0x00;
382     pin_modify -> bTeoPrologue[1] = 0x00;
383     pin_modify -> bTeoPrologue[2] = 0x00;
384 rousseau 1634 /* pin_modify -> ulDataLength = 0x00; we don't know the size yet */
385 rousseau 1631
386 rousseau 1300 /* APDU: 00 20 00 00 08 30 30 30 30 00 00 00 00 */
387 rousseau 1631 offset = 0;
388     pin_modify -> abData[offset++] = 0x00; /* CLA */
389 rousseau 1634 pin_modify -> abData[offset++] = 0x24; /* INS: CHANGE/UNBLOCK */
390 rousseau 1631 pin_modify -> abData[offset++] = 0x00; /* P1 */
391     pin_modify -> abData[offset++] = 0x00; /* P2 */
392 rousseau 1634 pin_modify -> abData[offset++] = 0x10; /* Lc: 2x8 data bytes */
393     pin_modify -> abData[offset++] = 0x30; /* '0' old PIN */
394 rousseau 1631 pin_modify -> abData[offset++] = 0x30; /* '0' */
395     pin_modify -> abData[offset++] = 0x30; /* '0' */
396     pin_modify -> abData[offset++] = 0x30; /* '0' */
397 rousseau 1634 pin_modify -> abData[offset++] = 0x00; /* '\0' */
398     pin_modify -> abData[offset++] = 0x00; /* '\0' */
399     pin_modify -> abData[offset++] = 0x00; /* '\0' */
400     pin_modify -> abData[offset++] = 0x00; /* '\0' */
401     pin_modify -> abData[offset++] = 0x30; /* '0' new PIN */
402 rousseau 1631 pin_modify -> abData[offset++] = 0x30; /* '0' */
403 rousseau 1634 pin_modify -> abData[offset++] = 0x30; /* '0' */
404     pin_modify -> abData[offset++] = 0x30; /* '0' */
405 rousseau 1631 pin_modify -> abData[offset++] = 0x00; /* '\0' */
406     pin_modify -> abData[offset++] = 0x00; /* '\0' */
407     pin_modify -> abData[offset++] = 0x00; /* '\0' */
408     pin_modify -> abData[offset++] = 0x00; /* '\0' */
409 rousseau 1669 pin_modify -> ulDataLength = HOST_TO_CCID_32(offset); /* APDU size */
410 rousseau 1300
411 rousseau 1634 length = sizeof(PIN_MODIFY_STRUCTURE) + offset -1; /* -1 because PIN_MODIFY_STRUCTURE contains the first byte of abData[] */
412    
413 rousseau 889 printf(" command:");
414 rousseau 1631 for (i=0; i<length; i++)
415 rousseau 889 printf(" %02X", bSendBuffer[i]);
416     printf("\n");
417 rousseau 972 printf("Enter your PIN: ");
418 rousseau 900 fflush(stdout);
419 rousseau 1634 rv = SCardControl(hCard, modify_ioctl, bSendBuffer,
420 rousseau 1631 length, bRecvBuffer, sizeof(bRecvBuffer), &length);
421 rousseau 889
422     printf(" card response:");
423     for (i=0; i<length; i++)
424     printf(" %02X", bRecvBuffer[i]);
425     printf("\n");
426     PCSC_ERROR_CONT(rv, "SCardControl")
427    
428 rousseau 972 {
429 rousseau 1067 #ifndef S_SPLINT_S
430 rousseau 972 fd_set fd;
431 rousseau 1067 #endif
432 rousseau 972 struct timeval timeout;
433    
434     FD_ZERO(&fd);
435     FD_SET(STDIN_FILENO, &fd); /* stdin */
436     timeout.tv_sec = 0; /* timeout = 0 */
437     timeout.tv_usec = 0;
438    
439     /* we only try to read stdin if the pinpad is on a keyboard
440     * we do not read stdin for a SPR 532 for example */
441     if (select(1, &fd, NULL, NULL, &timeout) > 0)
442     {
443     /* read the fake digits */
444     char in[10]; /* 4 digits + \n + \0 */
445 rousseau 1059 (void)fgets(in, sizeof(in), stdin);
446 rousseau 972
447     printf("keyboard sent: %s", in);
448     }
449     }
450    
451 rousseau 889 /* card disconnect */
452     rv = SCardDisconnect(hCard, SCARD_UNPOWER_CARD);
453     PCSC_ERROR_CONT(rv, "SCardDisconnect")
454    
455     end:
456     /* We try to leave things as clean as possible */
457     rv = SCardReleaseContext(hContext);
458     if (rv != SCARD_S_SUCCESS)
459     printf("SCardReleaseContext: %s (0x%lX)\n", pcsc_stringify_error(rv),
460     rv);
461    
462     /* free allocated memory */
463     free(mszReaders);
464     free(readers);
465    
466     return 0;
467     } /* main */
468    

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.5