/[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 1749 - (show annotations) (download)
Thu Nov 24 16:12:21 2005 UTC (7 years, 6 months ago) by rousseau
File MIME type: text/plain
File size: 15915 byte(s)
use a buffer of 40 instead of 10 to reader the keyboard since the PIN
may be longer than 8 digits
1 /*
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 #include <sys/time.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <PCSC/winscard.h>
30 #include <PCSC/reader.h>
31
32 #define VERIFY_PIN
33 #undef MODIFY_PIN
34
35 #ifndef TRUE
36 #define TRUE 1
37 #define FALSE 0
38 #endif
39
40 #define IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE SCARD_CTL_CODE(1)
41
42 /* PCSC error message pretty print */
43 #define PCSC_ERROR_EXIT(rv, text) \
44 if (rv != SCARD_S_SUCCESS) \
45 { \
46 printf(text ": %s (0x%lX)\n", pcsc_stringify_error(rv), rv); \
47 goto end; \
48 } \
49 else \
50 printf(text ": OK\n\n");
51
52 #define PCSC_ERROR_CONT(rv, text) \
53 if (rv != SCARD_S_SUCCESS) \
54 printf(text ": %s (0x%lX)\n", pcsc_stringify_error(rv), rv); \
55 else \
56 printf(text ": OK\n\n");
57
58 int main(int argc, char *argv[])
59 {
60 LONG rv;
61 SCARDCONTEXT hContext;
62 DWORD dwReaders;
63 LPTSTR mszReaders;
64 char *ptr, **readers = NULL;
65 int nbReaders;
66 SCARDHANDLE hCard;
67 DWORD dwActiveProtocol, dwReaderLen, dwState, dwProt, dwAtrLen;
68 BYTE pbAtr[MAX_ATR_SIZE] = "";
69 char pbReader[MAX_READERNAME] = "";
70 int reader_nb;
71 int i;
72 unsigned char bSendBuffer[MAX_BUFFER_SIZE];
73 unsigned char bRecvBuffer[MAX_BUFFER_SIZE];
74 DWORD send_length, length;
75 DWORD verify_ioctl = 0;
76 DWORD modify_ioctl = 0;
77 SCARD_IO_REQUEST pioRecvPci;
78 SCARD_IO_REQUEST pioSendPci;
79 PCSC_TLV_STRUCTURE *pcsc_tlv;
80 #if defined(VERIFY_PIN) | defined(MODIFY_PIN)
81 int offset;
82 #endif
83 #ifdef VERIFY_PIN
84 PIN_VERIFY_STRUCTURE *pin_verify;
85 #endif
86 #ifdef MODIFY_PIN
87 PIN_MODIFY_STRUCTURE *pin_modify;
88 #endif
89
90 printf("SCardControl sample code\n");
91 printf("V 1.1 2004-2005, Ludovic Rousseau <ludovic.rousseau@free.fr>\n");
92
93 printf("\nTHIS PROGRAM IS NOT DESIGNED AS A TESTING TOOL!\n");
94 printf("Do NOT use it unless you really know what you do.\n\n");
95
96 rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
97 if (rv != SCARD_S_SUCCESS)
98 {
99 printf("SCardEstablishContext: Cannot Connect to Resource Manager %lX\n", rv);
100 return 1;
101 }
102
103 /* Retrieve the available readers list */
104 rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
105 if (rv != SCARD_S_SUCCESS)
106 {
107 printf("SCardListReader: %lX\n", rv);
108 }
109
110 mszReaders = malloc(sizeof(char)*dwReaders);
111 if (mszReaders == NULL)
112 {
113 printf("malloc: not enough memory\n");
114 goto end;
115 }
116
117 rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
118 if (rv != SCARD_S_SUCCESS)
119 printf("SCardListReader: %lX\n", rv);
120
121 /* Extract readers from the null separated string and get the total
122 * number of readers */
123 nbReaders = 0;
124 ptr = mszReaders;
125 while (*ptr != '\0')
126 {
127 ptr += strlen(ptr)+1;
128 nbReaders++;
129 }
130
131 if (nbReaders == 0)
132 {
133 printf("No reader found\n");
134 goto end;
135 }
136
137 /* allocate the readers table */
138 readers = calloc(nbReaders, sizeof(char *));
139 if (NULL == readers)
140 {
141 printf("Not enough memory for readers[]\n");
142 goto end;
143 }
144
145 /* fill the readers table */
146 nbReaders = 0;
147 ptr = mszReaders;
148 while (*ptr != '\0')
149 {
150 printf("%d: %s\n", nbReaders, ptr);
151 readers[nbReaders] = ptr;
152 ptr += strlen(ptr)+1;
153 nbReaders++;
154 }
155
156 if (argc > 1)
157 {
158 reader_nb = atoi(argv[1]);
159 if (reader_nb < 0 || reader_nb >= nbReaders)
160 {
161 printf("Wrong reader index: %d\n", reader_nb);
162 goto end;
163 }
164 }
165 else
166 reader_nb = 0;
167
168 /* connect to a reader (even without a card) */
169 dwActiveProtocol = -1;
170 rv = SCardConnect(hContext, readers[reader_nb], SCARD_SHARE_DIRECT,
171 SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
172 printf(" Protocol: %ld\n", dwActiveProtocol);
173 PCSC_ERROR_EXIT(rv, "SCardConnect")
174
175 /* get GemPC firmware */
176 printf(" Get GemPC Firmware\n");
177
178 /* this is specific to Gemplus readers */
179 bSendBuffer[0] = 0x02;
180 rv = SCardControl(hCard, IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE, bSendBuffer,
181 1, bRecvBuffer, sizeof(bRecvBuffer), &length);
182
183 printf(" Firmware: ");
184 for (i=0; i<length; i++)
185 printf("%02X ", bRecvBuffer[i]);
186 printf("\n");
187
188 bRecvBuffer[length] = '\0';
189 printf(" Firmware: %s (length %ld bytes)\n", bRecvBuffer, length);
190
191 PCSC_ERROR_CONT(rv, "SCardControl")
192
193 /* get card status */
194 dwAtrLen = sizeof(pbAtr);
195 dwReaderLen = sizeof(pbReader);
196 rv = SCardStatus(hCard, pbReader, &dwReaderLen, &dwState, &dwProt,
197 pbAtr, &dwAtrLen);
198 printf(" Reader: %s (length %ld bytes)\n", pbReader, dwReaderLen);
199 printf(" State: 0x%lX\n", dwState);
200 printf(" Prot: %ld\n", dwProt);
201 printf(" ATR (length %ld bytes):", dwAtrLen);
202 for (i=0; i<dwAtrLen; i++)
203 printf(" %02X", pbAtr[i]);
204 printf("\n");
205 PCSC_ERROR_CONT(rv, "SCardStatus")
206
207 /* does the reader support PIN verification? */
208 rv = SCardControl(hCard, CM_IOCTL_GET_FEATURE_REQUEST, NULL, 0,
209 bRecvBuffer, sizeof(bRecvBuffer), &length);
210
211 printf(" TLV (%ld): ", length);
212 for (i=0; i<length; i++)
213 printf("%02X ", bRecvBuffer[i]);
214 printf("\n");
215
216 PCSC_ERROR_CONT(rv, "SCardControl(CM_IOCTL_GET_FEATURE_REQUEST)")
217
218 if (length % sizeof(PCSC_TLV_STRUCTURE))
219 {
220 printf("Inconsistent result! Bad TLV values!\n");
221 goto end;
222 }
223
224 /* get the number of elements instead of the complete size */
225 length /= sizeof(PCSC_TLV_STRUCTURE);
226
227 pcsc_tlv = (PCSC_TLV_STRUCTURE *)bRecvBuffer;
228 for (i = 0; i < length; i++)
229 {
230 if (pcsc_tlv[i].tag == FEATURE_VERIFY_PIN_DIRECT)
231 verify_ioctl = pcsc_tlv[i].value;
232 if (pcsc_tlv[i].tag == FEATURE_MODIFY_PIN_DIRECT)
233 modify_ioctl = pcsc_tlv[i].value;
234 }
235
236 if (0 == verify_ioctl)
237 {
238 printf("Reader %s does not support PIN verification\n",
239 readers[reader_nb]);
240 goto end;
241 }
242
243 /* connect to a reader (even without a card) */
244 dwActiveProtocol = -1;
245 rv = SCardReconnect(hCard, SCARD_SHARE_SHARED,
246 SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1, SCARD_UNPOWER_CARD,
247 &dwActiveProtocol);
248 printf(" Protocol: %ld\n", dwActiveProtocol);
249 PCSC_ERROR_EXIT(rv, "SCardReconnect")
250
251 switch(dwActiveProtocol)
252 {
253 case SCARD_PROTOCOL_T0:
254 pioSendPci = *SCARD_PCI_T0;
255 break;
256 case SCARD_PROTOCOL_T1:
257 pioSendPci = *SCARD_PCI_T1;
258 break;
259 default:
260 printf("Unknown protocol\n");
261 return -1;
262 }
263
264 /* APDU select applet */
265 printf("Select applet: ");
266 send_length = 11;
267 memcpy(bSendBuffer, "\x00\xA4\x04\x00\x06\xA0\x00\x00\x00\x18\xFF",
268 send_length);
269 for (i=0; i<send_length; i++)
270 printf(" %02X", bSendBuffer[i]);
271 printf("\n");
272 length = sizeof(bRecvBuffer);
273 rv = SCardTransmit(hCard, &pioSendPci, bSendBuffer, send_length,
274 &pioRecvPci, bRecvBuffer, &length);
275 printf(" card response:");
276 for (i=0; i<length; i++)
277 printf(" %02X", bRecvBuffer[i]);
278 printf("\n");
279 PCSC_ERROR_EXIT(rv, "SCardTransmit")
280 if ((bRecvBuffer[0] != 0x90) || (bRecvBuffer[1] != 0x00))
281 {
282 printf("Error: test applet not found!\n");
283 goto end;
284 }
285
286 #ifdef VERIFY_PIN
287 /* verify PIN */
288 printf(" Secure verify PIN\n");
289 pin_verify = (PIN_VERIFY_STRUCTURE *)bSendBuffer;
290
291 /* PC/SC v2.0.2 Part 10 PIN verification data structure */
292 pin_verify -> bTimerOut = 0x00;
293 pin_verify -> bTimerOut2 = 0x00;
294 pin_verify -> bmFormatString = 0x82;
295 pin_verify -> bmPINBlockString = 0x04;
296 pin_verify -> bmPINLengthFormat = 0x00;
297 pin_verify -> wPINMaxExtraDigit = HOST_TO_CCID_16(0x0408); /* Min Max */
298 pin_verify -> bEntryValidationCondition = 0x02; /* validation key pressed */
299 pin_verify -> bNumberMessage = 0x01;
300 pin_verify -> wLangId = HOST_TO_CCID_16(0x0904);
301 pin_verify -> bMsgIndex = 0x00;
302 pin_verify -> bTeoPrologue[0] = 0x00;
303 pin_verify -> bTeoPrologue[1] = 0x00;
304 pin_verify -> bTeoPrologue[2] = 0x00;
305 /* pin_verify -> ulDataLength = 0x00; we don't know the size yet */
306
307 /* APDU: 00 20 00 00 08 30 30 30 30 00 00 00 00 */
308 offset = 0;
309 pin_verify -> abData[offset++] = 0x00; /* CLA */
310 pin_verify -> abData[offset++] = 0x20; /* INS: VERIFY */
311 pin_verify -> abData[offset++] = 0x00; /* P1 */
312 pin_verify -> abData[offset++] = 0x00; /* P2 */
313 pin_verify -> abData[offset++] = 0x08; /* Lc: 8 data bytes */
314 pin_verify -> abData[offset++] = 0x30; /* '0' */
315 pin_verify -> abData[offset++] = 0x30; /* '0' */
316 pin_verify -> abData[offset++] = 0x30; /* '0' */
317 pin_verify -> abData[offset++] = 0x30; /* '0' */
318 pin_verify -> abData[offset++] = 0x00; /* '\0' */
319 pin_verify -> abData[offset++] = 0x00; /* '\0' */
320 pin_verify -> abData[offset++] = 0x00; /* '\0' */
321 pin_verify -> abData[offset++] = 0x00; /* '\0' */
322 pin_verify -> ulDataLength = HOST_TO_CCID_32(offset); /* APDU size */
323
324 length = sizeof(PIN_VERIFY_STRUCTURE) + offset -1; /* -1 because PIN_VERIFY_STRUCTURE contains the first byte of abData[] */
325
326 printf(" command:");
327 for (i=0; i<length; i++)
328 printf(" %02X", bSendBuffer[i]);
329 printf("\n");
330 printf("Enter your PIN: ");
331 fflush(stdout);
332 rv = SCardControl(hCard, verify_ioctl, bSendBuffer,
333 length, bRecvBuffer, sizeof(bRecvBuffer), &length);
334
335 {
336 #ifndef S_SPLINT_S
337 fd_set fd;
338 #endif
339 struct timeval timeout;
340
341 FD_ZERO(&fd);
342 FD_SET(STDIN_FILENO, &fd); /* stdin */
343 timeout.tv_sec = 0; /* timeout = 0 */
344 timeout.tv_usec = 0;
345
346 /* we only try to read stdin if the pinpad is on a keyboard
347 * we do not read stdin for a SPR 532 for example */
348 if (select(1, &fd, NULL, NULL, &timeout) > 0)
349 {
350 /* read the fake digits */
351 char in[40]; /* 4 digits + \n + \0 */
352 (void)fgets(in, sizeof(in), stdin);
353
354 printf("keyboard sent: %s", in);
355 }
356 else
357 /* if it is not a keyboard */
358 printf("\n");
359 }
360
361 printf(" card response:");
362 for (i=0; i<length; i++)
363 printf(" %02X", bRecvBuffer[i]);
364 printf("\n");
365 PCSC_ERROR_CONT(rv, "SCardControl")
366
367 /* verify PIN dump */
368 printf("\nverify PIN dump: ");
369 send_length = 5;
370 memcpy(bSendBuffer, "\x00\x40\x00\x00\xFF",
371 send_length);
372 for (i=0; i<send_length; i++)
373 printf(" %02X", bSendBuffer[i]);
374 printf("\n");
375 length = sizeof(bRecvBuffer);
376 rv = SCardTransmit(hCard, &pioSendPci, bSendBuffer, send_length,
377 &pioRecvPci, bRecvBuffer, &length);
378 printf(" card response:");
379 for (i=0; i<length; i++)
380 printf(" %02X", bRecvBuffer[i]);
381 printf("\n");
382 PCSC_ERROR_EXIT(rv, "SCardTransmit")
383
384 if ((2 == length) && (0x6C == bRecvBuffer[0]))
385 {
386 printf("\nverify PIN dump: ");
387 send_length = 5;
388 memcpy(bSendBuffer, "\x00\x40\x00\x00\xFF",
389 send_length);
390 bSendBuffer[4] = bRecvBuffer[1];
391 for (i=0; i<send_length; i++)
392 printf(" %02X", bSendBuffer[i]);
393 printf("\n");
394 length = sizeof(bRecvBuffer);
395 rv = SCardTransmit(hCard, &pioSendPci, bSendBuffer, send_length,
396 &pioRecvPci, bRecvBuffer, &length);
397 printf(" card response:");
398 for (i=0; i<length; i++)
399 printf(" %02X", bRecvBuffer[i]);
400 printf("\n");
401 PCSC_ERROR_EXIT(rv, "SCardTransmit")
402 }
403 #endif
404
405 /* check if the reader supports Modify PIN */
406 if (0 == modify_ioctl)
407 {
408 printf("Reader %s does not support PIN modification\n",
409 readers[reader_nb]);
410 goto end;
411 }
412
413 #ifdef MODIFY_PIN
414 /* Modify PIN */
415 printf(" Secure modify PIN\n");
416 pin_modify = (PIN_MODIFY_STRUCTURE *)bSendBuffer;
417
418 /* PC/SC v2.0.2 Part 10 PIN verification data structure */
419 pin_modify -> bTimerOut = 0x00;
420 pin_modify -> bTimerOut2 = 0x00;
421 pin_modify -> bmFormatString = 0x82;
422 pin_modify -> bmPINBlockString = 0x04;
423 pin_modify -> bmPINLengthFormat = 0x00;
424 pin_modify -> bInsertionOffsetOld = 0x00; /* offset from APDU start */
425 pin_modify -> bInsertionOffsetNew = 0x04; /* offset from APDU start */
426 pin_modify -> wPINMaxExtraDigit = HOST_TO_CCID_16(0x0404); /* Min Max */
427 pin_modify -> bConfirmPIN = 0x03; /* b0 set = confirmation requested */
428 /* b1 set = current PIN entry requested */
429 pin_modify -> bEntryValidationCondition = 0x02; /* validation key pressed */
430 pin_modify -> bNumberMessage = 0x03; /* 3 for GemPC Pinpad, 0 for SPR532 */
431 pin_modify -> wLangId = HOST_TO_CCID_16(0x0904);
432 pin_modify -> bMsgIndex1 = 0x00;
433 pin_modify -> bMsgIndex2 = 0x00;
434 pin_modify -> bMsgIndex3 = 0x00;
435 pin_modify -> bTeoPrologue[0] = 0x00;
436 pin_modify -> bTeoPrologue[1] = 0x00;
437 pin_modify -> bTeoPrologue[2] = 0x00;
438 /* pin_modify -> ulDataLength = 0x00; we don't know the size yet */
439
440 /* APDU: 00 20 00 00 08 30 30 30 30 00 00 00 00 */
441 offset = 0;
442 pin_modify -> abData[offset++] = 0x00; /* CLA */
443 pin_modify -> abData[offset++] = 0x24; /* INS: CHANGE/UNBLOCK */
444 pin_modify -> abData[offset++] = 0x00; /* P1 */
445 pin_modify -> abData[offset++] = 0x00; /* P2 */
446 pin_modify -> abData[offset++] = 0x08; /* Lc: 2x8 data bytes */
447 pin_modify -> abData[offset++] = 0x30; /* '0' old PIN */
448 pin_modify -> abData[offset++] = 0x30; /* '0' */
449 pin_modify -> abData[offset++] = 0x30; /* '0' */
450 pin_modify -> abData[offset++] = 0x30; /* '0' */
451 pin_modify -> abData[offset++] = 0x30; /* '0' new PIN */
452 pin_modify -> abData[offset++] = 0x30; /* '0' */
453 pin_modify -> abData[offset++] = 0x30; /* '0' */
454 pin_modify -> abData[offset++] = 0x30; /* '0' */
455 pin_modify -> ulDataLength = HOST_TO_CCID_32(offset); /* APDU size */
456
457 length = sizeof(PIN_MODIFY_STRUCTURE) + offset -1; /* -1 because PIN_MODIFY_STRUCTURE contains the first byte of abData[] */
458
459 printf(" command:");
460 for (i=0; i<length; i++)
461 printf(" %02X", bSendBuffer[i]);
462 printf("\n");
463 printf("Enter your PIN: ");
464 fflush(stdout);
465 rv = SCardControl(hCard, modify_ioctl, bSendBuffer,
466 length, bRecvBuffer, sizeof(bRecvBuffer), &length);
467
468 printf(" card response:");
469 for (i=0; i<length; i++)
470 printf(" %02X", bRecvBuffer[i]);
471 printf("\n");
472 PCSC_ERROR_CONT(rv, "SCardControl")
473
474 {
475 #ifndef S_SPLINT_S
476 fd_set fd;
477 #endif
478 struct timeval timeout;
479
480 FD_ZERO(&fd);
481 FD_SET(STDIN_FILENO, &fd); /* stdin */
482 timeout.tv_sec = 0; /* timeout = 0 */
483 timeout.tv_usec = 0;
484
485 /* we only try to read stdin if the pinpad is on a keyboard
486 * we do not read stdin for a SPR 532 for example */
487 if (select(1, &fd, NULL, NULL, &timeout) > 0)
488 {
489 /* read the fake digits */
490 char in[40]; /* 4 digits + \n + \0 */
491 (void)fgets(in, sizeof(in), stdin);
492
493 printf("keyboard sent: %s", in);
494 }
495 }
496
497 /* modify PIN dump */
498 printf("\nmodify PIN dump: ");
499 send_length = 5;
500 memcpy(bSendBuffer, "\x00\x40\x00\x00\xFF",
501 send_length);
502 for (i=0; i<send_length; i++)
503 printf(" %02X", bSendBuffer[i]);
504 printf("\n");
505 length = sizeof(bRecvBuffer);
506 rv = SCardTransmit(hCard, &pioSendPci, bSendBuffer, send_length,
507 &pioRecvPci, bRecvBuffer, &length);
508 printf(" card response:");
509 for (i=0; i<length; i++)
510 printf(" %02X", bRecvBuffer[i]);
511 printf("\n");
512 PCSC_ERROR_EXIT(rv, "SCardTransmit")
513
514 if ((2 == length) && (0x6C == bRecvBuffer[0]))
515 {
516 printf("\nverify PIN dump: ");
517 send_length = 5;
518 memcpy(bSendBuffer, "\x00\x40\x00\x00\xFF",
519 send_length);
520 bSendBuffer[4] = bRecvBuffer[1];
521 for (i=0; i<send_length; i++)
522 printf(" %02X", bSendBuffer[i]);
523 printf("\n");
524 length = sizeof(bRecvBuffer);
525 rv = SCardTransmit(hCard, &pioSendPci, bSendBuffer, send_length,
526 &pioRecvPci, bRecvBuffer, &length);
527 printf(" card response:");
528 for (i=0; i<length; i++)
529 printf(" %02X", bRecvBuffer[i]);
530 printf("\n");
531 PCSC_ERROR_EXIT(rv, "SCardTransmit")
532 }
533 #endif
534
535 /* card disconnect */
536 rv = SCardDisconnect(hCard, SCARD_UNPOWER_CARD);
537 PCSC_ERROR_CONT(rv, "SCardDisconnect")
538
539 end:
540 /* We try to leave things as clean as possible */
541 rv = SCardReleaseContext(hContext);
542 if (rv != SCARD_S_SUCCESS)
543 printf("SCardReleaseContext: %s (0x%lX)\n", pcsc_stringify_error(rv),
544 rv);
545
546 /* free allocated memory */
547 free(mszReaders);
548 free(readers);
549
550 return 0;
551 } /* main */
552

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.5