Initial commit
[platform/upstream/ccid.git] / examples / scardcontrol.c
1 /*
2     scardcontrol.c: sample code to use/test SCardControl() API
3     Copyright (C) 2004-2019   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 along
16         with this program; if not, write to the Free Software Foundation, Inc., 51
17         Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <sys/time.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <arpa/inet.h>
26 #ifdef __APPLE__
27 #include <PCSC/winscard.h>
28 #include <PCSC/wintypes.h>
29 #else
30 #include <winscard.h>
31 #endif
32 #include <reader.h>
33
34 #include "PCSCv2part10.h"
35
36 #define VERIFY_PIN
37 #undef MODIFY_PIN
38 #undef GET_GEMPC_FIRMWARE
39
40 #ifndef TRUE
41 #define TRUE 1
42 #define FALSE 0
43 #endif
44
45 #define IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE     SCARD_CTL_CODE(1)
46
47 #define BLUE "\33[34m"
48 #define RED "\33[31m"
49 #define BRIGHT_RED "\33[01;31m"
50 #define GREEN "\33[32m"
51 #define NORMAL "\33[0m"
52 #define MAGENTA "\33[35m"
53
54 /* DWORD printf(3) format */
55 #ifdef __APPLE__
56 /* Apple defines DWORD as uint32_t so %d is correct */
57 #define LF
58 #else
59 /* pcsc-lite defines DWORD as unsigned long so %ld is correct */
60 #define LF "l"
61 #endif
62
63 /* PCSC error message pretty print */
64 #define PCSC_ERROR_EXIT(rv, text) \
65 if (rv != SCARD_S_SUCCESS) \
66 { \
67         printf(text ": " RED "%s (0x%"LF"X)\n" NORMAL, pcsc_stringify_error(rv), rv); \
68         goto end; \
69 } \
70 else \
71         printf(text ": " BLUE "OK\n\n" NORMAL);
72
73 #define PCSC_ERROR_CONT(rv, text) \
74 if (rv != SCARD_S_SUCCESS) \
75         printf(text ": " RED "%s (0x%"LF"X)\n" NORMAL, pcsc_stringify_error(rv), rv); \
76 else \
77         printf(text ": " BLUE "OK\n\n" NORMAL);
78
79 #define PRINT_GREEN(text, value) \
80         printf("%s: " GREEN "%s\n" NORMAL, text, value)
81
82 #define PRINT_GREEN_DEC(text, value) \
83         printf("%s: " GREEN "%d\n" NORMAL, text, value)
84
85 #define PRINT_RED_DEC(text, value) \
86         printf("%s: " RED "%d\n" NORMAL, text, value)
87
88 #define PRINT_GREEN_HEX2(text, value) \
89         printf("%s: " GREEN "0x%02X\n" NORMAL, text, value)
90
91 #define PRINT_GREEN_HEX4(text, value) \
92         printf("%s: " GREEN "0x%04X\n" NORMAL, text, value)
93
94 static void parse_properties(unsigned char *bRecvBuffer, int length)
95 {
96         unsigned char *p;
97         int i;
98
99         p = bRecvBuffer;
100         while (p-bRecvBuffer < length)
101         {
102                 int tag, len, value;
103
104                 tag = *p++;
105                 len = *p++;
106
107                 switch(len)
108                 {
109                         case 1:
110                                 value = *p;
111                                 break;
112                         case 2:
113                                 value = *p + (*(p+1)<<8);
114                                 break;
115                         case 4:
116                                 value = *p + (*(p+1)<<8) + (*(p+2)<<16) + (*(p+3)<<24);
117                                 break;
118                         default:
119                                 value = -1;
120                 }
121
122                 switch(tag)
123                 {
124                         case PCSCv2_PART10_PROPERTY_wLcdLayout:
125                                 PRINT_GREEN_HEX4(" wLcdLayout", value);
126                                 break;
127                         case PCSCv2_PART10_PROPERTY_bEntryValidationCondition:
128                                 PRINT_GREEN_HEX2(" bEntryValidationCondition", value);
129                                 break;
130                         case PCSCv2_PART10_PROPERTY_bTimeOut2:
131                                 PRINT_GREEN_HEX2(" bTimeOut2", value);
132                                 break;
133                         case PCSCv2_PART10_PROPERTY_wLcdMaxCharacters:
134                                 PRINT_GREEN_HEX4(" wLcdMaxCharacters", value);
135                                 break;
136                         case PCSCv2_PART10_PROPERTY_wLcdMaxLines:
137                                 PRINT_GREEN_HEX4(" wLcdMaxLines", value);
138                                 break;
139                         case PCSCv2_PART10_PROPERTY_bMinPINSize:
140                                 PRINT_GREEN_HEX2(" bMinPINSize", value);
141                                 break;
142                         case PCSCv2_PART10_PROPERTY_bMaxPINSize:
143                                 PRINT_GREEN_HEX2(" bMaxPINSize", value);
144                                 break;
145                         case PCSCv2_PART10_PROPERTY_sFirmwareID:
146                                 printf(" sFirmwareID: " GREEN);
147                                 for (i=0; i<len; i++)
148                                         putchar(p[i]);
149                                 printf(NORMAL "\n");
150                                 break;
151                         case PCSCv2_PART10_PROPERTY_bPPDUSupport:
152                                 PRINT_GREEN_HEX2(" bPPDUSupport", value);
153                                 if (value & 1)
154                                         printf("  PPDU is supported over SCardControl using FEATURE_CCID_ESC_COMMAND\n");
155                                 if (value & 2)
156                                         printf("  PPDU is supported over SCardTransmit\n");
157                                 break;
158                         case PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize:
159                                 PRINT_GREEN_DEC(" dwMaxAPDUDataSize", value);
160                                 break;
161                         case PCSCv2_PART10_PROPERTY_wIdVendor:
162                                 PRINT_GREEN_HEX2(" wIdVendor", value);
163                                 break;
164                         case PCSCv2_PART10_PROPERTY_wIdProduct:
165                                 PRINT_GREEN_HEX2(" wIdProduct", value);
166                                 break;
167                         default:
168                                 printf(" Unknown tag: 0x%02X (length = %d)\n", tag, len);
169                 }
170
171                 p += len;
172         }
173 } /* parse_properties */
174
175
176 static const char *pinpad_return_codes(int length,
177         unsigned char bRecvBuffer[])
178 {
179         const char * ret = "UNKNOWN";
180
181         if (length < 2)
182                 return "";
183
184         if ((0x90 == bRecvBuffer[0]) && (0x00 == bRecvBuffer[1]))
185                 ret = "Success";
186
187         if (0x64 == bRecvBuffer[0])
188         {
189                 switch (bRecvBuffer[1])
190                 {
191                         case 0x00:
192                                 ret = "Timeout";
193                                 break;
194
195                         case 0x01:
196                                 ret = "Cancelled by user";
197                                 break;
198
199                         case 0x02:
200                                 ret = "PIN mismatch";
201                                 break;
202
203                         case 0x03:
204                                 ret = "Too short or too long PIN";
205                                 break;
206                 }
207         }
208
209         return ret;
210 }
211
212 int main(int argc, char *argv[])
213 {
214         LONG rv;
215         SCARDCONTEXT hContext;
216         DWORD dwReaders;
217         LPSTR mszReaders = NULL;
218         char *ptr, **readers = NULL;
219         int nbReaders;
220         SCARDHANDLE hCard;
221         DWORD dwActiveProtocol, dwReaderLen, dwState, dwProt, dwAtrLen;
222         BYTE pbAtr[MAX_ATR_SIZE] = "";
223         char pbReader[MAX_READERNAME] = "";
224         int reader_nb;
225         unsigned int i;
226         unsigned char bSendBuffer[MAX_BUFFER_SIZE];
227         unsigned char bRecvBuffer[MAX_BUFFER_SIZE];
228         DWORD send_length, length;
229         DWORD verify_ioctl = 0;
230         DWORD modify_ioctl = 0;
231         DWORD pin_properties_ioctl = 0;
232         DWORD mct_readerdirect_ioctl = 0;
233         DWORD properties_in_tlv_ioctl = 0;
234         DWORD ccid_esc_command = 0;
235         SCARD_IO_REQUEST pioRecvPci;
236         SCARD_IO_REQUEST pioSendPci;
237         PCSC_TLV_STRUCTURE *pcsc_tlv;
238 #if defined(VERIFY_PIN) | defined(MODIFY_PIN)
239         int offset;
240 #endif
241 #ifdef VERIFY_PIN
242         PIN_VERIFY_STRUCTURE *pin_verify;
243 #endif
244 #ifdef MODIFY_PIN
245         PIN_MODIFY_STRUCTURE *pin_modify;
246 #endif
247         char error;
248         int PIN_min_size = 4;
249         int PIN_max_size = 8;
250
251         /* table for bEntryValidationCondition
252          * 0x01: Max size reached
253          * 0x02: Validation key pressed
254          * 0x04: Timeout occurred
255          */
256         int bEntryValidationCondition = 7;
257
258         printf("SCardControl sample code\n");
259         printf("V 1.4 © 2004-2010, Ludovic Rousseau <ludovic.rousseau@free.fr>\n\n");
260
261         printf(MAGENTA "THIS PROGRAM IS NOT DESIGNED AS A TESTING TOOL!\n");
262         printf("Do NOT use it unless you really know what you do.\n\n" NORMAL);
263
264         rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
265         if (rv != SCARD_S_SUCCESS)
266         {
267                 printf("SCardEstablishContext: Cannot Connect to Resource Manager %"LF"X\n", rv);
268                 return 1;
269         }
270
271         /* Retrieve the available readers list */
272         rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
273         PCSC_ERROR_EXIT(rv, "SCardListReaders")
274
275         mszReaders = malloc(sizeof(char)*dwReaders);
276         if (mszReaders == NULL)
277         {
278                 printf("malloc: not enough memory\n");
279                 goto end;
280         }
281
282         rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
283         if (rv != SCARD_S_SUCCESS)
284                 printf("SCardListReader: %"LF"X\n", rv);
285
286         /* Extract readers from the null separated string and get the total
287          * number of readers */
288         nbReaders = 0;
289         ptr = mszReaders;
290         while (*ptr != '\0')
291         {
292                 ptr += strlen(ptr)+1;
293                 nbReaders++;
294         }
295
296         if (nbReaders == 0)
297         {
298                 printf("No reader found\n");
299                 goto end;
300         }
301
302         /* allocate the readers table */
303         readers = calloc(nbReaders, sizeof(char *));
304         if (NULL == readers)
305         {
306                 printf("Not enough memory for readers[]\n");
307                 goto end;
308         }
309
310         /* fill the readers table */
311         nbReaders = 0;
312         ptr = mszReaders;
313         printf("Available readers (use command line argument to select)\n");
314         while (*ptr != '\0')
315         {
316                 printf("%d: %s\n", nbReaders, ptr);
317                 readers[nbReaders] = ptr;
318                 ptr += strlen(ptr)+1;
319                 nbReaders++;
320         }
321         printf("\n");
322
323         if (argc > 1)
324         {
325                 reader_nb = atoi(argv[1]);
326                 if (reader_nb < 0 || reader_nb >= nbReaders)
327                 {
328                         printf("Wrong reader index: %d\n", reader_nb);
329                         goto end;
330                 }
331         }
332         else
333                 reader_nb = 0;
334
335         /* connect to a reader (even without a card) */
336         dwActiveProtocol = -1;
337         printf("Using reader: " GREEN "%s\n" NORMAL, readers[reader_nb]);
338         rv = SCardConnect(hContext, readers[reader_nb], SCARD_SHARE_SHARED,
339                 SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
340         printf(" Protocol: " GREEN "%"LF"d\n" NORMAL, dwActiveProtocol);
341         PCSC_ERROR_EXIT(rv, "SCardConnect")
342
343 #ifdef GET_GEMPC_FIRMWARE
344         /* get GemPC firmware */
345         printf(" Get GemPC Firmware\n");
346
347         /* this is specific to Gemalto readers */
348         bSendBuffer[0] = 0x02;
349         rv = SCardControl(hCard, IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE, bSendBuffer,
350                 1, bRecvBuffer, sizeof(bRecvBuffer), &length);
351
352         printf(" Firmware: " GREEN);
353         for (i=0; i<length; i++)
354                 printf("%02X ", bRecvBuffer[i]);
355         printf(NORMAL "\n");
356
357         bRecvBuffer[length] = '\0';
358         printf(" Firmware: " GREEN "%s" NORMAL" (length " GREEN "%ld" NORMAL " bytes)\n", bRecvBuffer, length);
359
360         PCSC_ERROR_CONT(rv, "SCardControl")
361 #endif
362
363         /* does the reader support PIN verification? */
364         rv = SCardControl(hCard, CM_IOCTL_GET_FEATURE_REQUEST, NULL, 0,
365                 bRecvBuffer, sizeof(bRecvBuffer), &length);
366         PCSC_ERROR_EXIT(rv, "SCardControl")
367
368         printf(" TLV (%"LF"d): " GREEN, length);
369         for (i=0; i<length; i++)
370                 printf("%02X ", bRecvBuffer[i]);
371         printf(NORMAL "\n");
372
373         PCSC_ERROR_CONT(rv, "SCardControl(CM_IOCTL_GET_FEATURE_REQUEST)")
374
375         if (length % sizeof(PCSC_TLV_STRUCTURE))
376         {
377                 printf("Inconsistent result! Bad TLV values!\n");
378                 goto end;
379         }
380
381         /* get the number of elements instead of the complete size */
382         length /= sizeof(PCSC_TLV_STRUCTURE);
383
384         pcsc_tlv = (PCSC_TLV_STRUCTURE *)bRecvBuffer;
385         for (i = 0; i < length; i++)
386         {
387                 switch (pcsc_tlv[i].tag)
388                 {
389                         case FEATURE_VERIFY_PIN_DIRECT:
390                                 PRINT_GREEN("Reader supports", "FEATURE_VERIFY_PIN_DIRECT");
391                                 verify_ioctl = ntohl(pcsc_tlv[i].value);
392                                 break;
393                         case FEATURE_MODIFY_PIN_DIRECT:
394                                 PRINT_GREEN("Reader supports", "FEATURE_MODIFY_PIN_DIRECT");
395                                 modify_ioctl = ntohl(pcsc_tlv[i].value);
396                                 break;
397                         case FEATURE_IFD_PIN_PROPERTIES:
398                                 PRINT_GREEN("Reader supports", "FEATURE_IFD_PIN_PROPERTIES");
399                                 pin_properties_ioctl = ntohl(pcsc_tlv[i].value);
400                                 break;
401                         case FEATURE_MCT_READER_DIRECT:
402                                 PRINT_GREEN("Reader supports", "FEATURE_MCT_READER_DIRECT");
403                                 mct_readerdirect_ioctl = ntohl(pcsc_tlv[i].value);
404                                 break;
405                         case FEATURE_GET_TLV_PROPERTIES:
406                                 PRINT_GREEN("Reader supports", "FEATURE_GET_TLV_PROPERTIES");
407                                 properties_in_tlv_ioctl = ntohl(pcsc_tlv[i].value);
408                                 break;
409                         case FEATURE_CCID_ESC_COMMAND:
410                                 PRINT_GREEN("Reader supports", "FEATURE_CCID_ESC_COMMAND");
411                                 ccid_esc_command = ntohl(pcsc_tlv[i].value);
412                                 break;
413                         default:
414                                 PRINT_RED_DEC("Can't parse tag", pcsc_tlv[i].tag);
415                 }
416         }
417         printf("\n");
418
419         if (properties_in_tlv_ioctl)
420         {
421                 int value;
422                 int ret;
423
424                 rv = SCardControl(hCard, properties_in_tlv_ioctl, NULL, 0,
425                         bRecvBuffer, sizeof(bRecvBuffer), &length);
426                 PCSC_ERROR_CONT(rv, "SCardControl(GET_TLV_PROPERTIES)")
427
428                 printf("GET_TLV_PROPERTIES (" GREEN "%"LF"d" NORMAL "): " GREEN, length);
429                 for (i=0; i<length; i++)
430                         printf("%02X ", bRecvBuffer[i]);
431                 printf(NORMAL "\n");
432
433                 printf("\nDisplay all the properties:\n");
434                 parse_properties(bRecvBuffer, length);
435
436                 printf("\nFind a specific property:\n");
437                 ret = PCSCv2Part10_find_TLV_property_by_tag_from_buffer(bRecvBuffer, length, PCSCv2_PART10_PROPERTY_wIdVendor, &value);
438                 if (ret)
439                         PRINT_RED_DEC(" wIdVendor", ret);
440                 else
441                         PRINT_GREEN_HEX4(" wIdVendor", value);
442
443                 ret = PCSCv2Part10_find_TLV_property_by_tag_from_hcard(hCard, PCSCv2_PART10_PROPERTY_wIdProduct, &value);
444                 if (ret)
445                         PRINT_RED_DEC(" wIdProduct", ret);
446                 else
447                         PRINT_GREEN_HEX4(" wIdProduct", value);
448
449                 ret = PCSCv2Part10_find_TLV_property_by_tag_from_hcard(hCard, PCSCv2_PART10_PROPERTY_bMinPINSize, &value);
450                 if (0 == ret)
451                 {
452                         PIN_min_size = value;
453                         PRINT_GREEN_DEC(" PIN min size defined", PIN_min_size);
454                 }
455
456
457                 ret = PCSCv2Part10_find_TLV_property_by_tag_from_hcard(hCard, PCSCv2_PART10_PROPERTY_bMaxPINSize, &value);
458                 if (0 == ret)
459                 {
460                         PIN_max_size = value;
461                         PRINT_GREEN_DEC(" PIN max size defined", PIN_max_size);
462                 }
463
464                 ret = PCSCv2Part10_find_TLV_property_by_tag_from_hcard(hCard, PCSCv2_PART10_PROPERTY_bEntryValidationCondition, &value);
465                 if (0 == ret)
466                 {
467                         bEntryValidationCondition = value;
468                         PRINT_GREEN_DEC(" Entry Validation Condition defined",
469                                 bEntryValidationCondition);
470                 }
471
472                 printf("\n");
473         }
474
475         if (mct_readerdirect_ioctl)
476         {
477                 char secoder_info[] = { 0x20, 0x70, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 };
478
479                 rv = SCardControl(hCard, mct_readerdirect_ioctl, secoder_info,
480                         sizeof(secoder_info), bRecvBuffer, sizeof(bRecvBuffer), &length);
481                 PCSC_ERROR_CONT(rv, "SCardControl(MCT_READER_DIRECT)")
482
483                 printf("MCT_READER_DIRECT (%"LF"d): ", length);
484                 for (i=0; i<length; i++)
485                         printf("%02X ", bRecvBuffer[i]);
486                 printf("\n");
487         }
488
489         if (pin_properties_ioctl)
490         {
491                 PIN_PROPERTIES_STRUCTURE *pin_properties;
492
493                 rv = SCardControl(hCard, pin_properties_ioctl, NULL, 0,
494                         bRecvBuffer, sizeof(bRecvBuffer), &length);
495                 PCSC_ERROR_CONT(rv, "SCardControl(pin_properties_ioctl)")
496
497                 printf("PIN PROPERTIES (" GREEN "%"LF"d" NORMAL "): " GREEN, length);
498                 for (i=0; i<length; i++)
499                         printf("%02X ", bRecvBuffer[i]);
500                 printf(NORMAL "\n");
501
502                 pin_properties = (PIN_PROPERTIES_STRUCTURE *)bRecvBuffer;
503                 bEntryValidationCondition = pin_properties ->   bEntryValidationCondition;
504                 PRINT_GREEN_HEX4(" wLcdLayout", pin_properties -> wLcdLayout);
505                 PRINT_GREEN_DEC(" bEntryValidationCondition", bEntryValidationCondition);
506                 PRINT_GREEN_DEC(" bTimeOut2", pin_properties -> bTimeOut2);
507
508                 printf("\n");
509         }
510
511 #ifdef GET_GEMPC_FIRMWARE
512         if (ccid_esc_command)
513         {
514                 /* get GemPC firmware */
515                 printf("Get GemPC Firmware\n");
516
517                 /* this is specific to Gemalto readers */
518                 bSendBuffer[0] = 0x02;
519                 rv = SCardControl(hCard, ccid_esc_command, bSendBuffer,
520                         1, bRecvBuffer, sizeof(bRecvBuffer), &length);
521
522                 printf(" Firmware: " GREEN);
523                 for (i=0; i<length; i++)
524                         printf("%02X ", bRecvBuffer[i]);
525                 printf(NORMAL "\n");
526
527                 bRecvBuffer[length] = '\0';
528                 printf(" Firmware: " GREEN "%s" NORMAL" (length " GREEN "%ld" NORMAL " bytes)\n", bRecvBuffer, length);
529
530                 PCSC_ERROR_CONT(rv, "SCardControl")
531         }
532 #else
533         (void)ccid_esc_command;
534 #endif
535
536         if (0 == verify_ioctl)
537         {
538                 printf("Reader %s does not support PIN verification\n",
539                         readers[reader_nb]);
540                 goto end;
541         }
542
543         /* get card status */
544         dwAtrLen = sizeof(pbAtr);
545         dwReaderLen = sizeof(pbReader);
546         rv = SCardStatus(hCard, pbReader, &dwReaderLen, &dwState, &dwProt,
547                 pbAtr, &dwAtrLen);
548         printf(" Reader: %s (length %"LF"d bytes)\n", pbReader, dwReaderLen);
549         printf(" State: 0x%04"LF"X\n", dwState);
550         printf(" Prot: %"LF"d\n", dwProt);
551         printf(" ATR (length %"LF"d bytes):", dwAtrLen);
552         for (i=0; i<dwAtrLen; i++)
553                 printf(" %02X", pbAtr[i]);
554         printf("\n");
555         PCSC_ERROR_CONT(rv, "SCardStatus")
556
557         if (dwState & SCARD_ABSENT)
558         {
559                 printf("No card inserted\n");
560                 goto end;
561         }
562
563         /* re-connect to a reader (with a card) */
564         dwActiveProtocol = -1;
565         rv = SCardReconnect(hCard, SCARD_SHARE_SHARED,
566                 SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1, SCARD_LEAVE_CARD,
567                 &dwActiveProtocol);
568         printf(" Protocol: %"LF"d\n", dwActiveProtocol);
569         PCSC_ERROR_EXIT(rv, "SCardReconnect")
570
571         switch(dwActiveProtocol)
572         {
573                 case SCARD_PROTOCOL_T0:
574                         pioSendPci = *SCARD_PCI_T0;
575                         break;
576                 case SCARD_PROTOCOL_T1:
577                         pioSendPci = *SCARD_PCI_T1;
578                         break;
579                 default:
580                         printf("Unknown protocol. No card present?\n");
581                         return -1;
582         }
583
584         /* APDU select applet */
585         printf("Select applet:");
586         send_length = 11;
587         memcpy(bSendBuffer, "\x00\xA4\x04\x00\x06\xA0\x00\x00\x00\x18\xFF",
588                 send_length);
589         for (i=0; i<send_length; i++)
590                 printf(" %02X", bSendBuffer[i]);
591         printf("\n");
592         length = sizeof(bRecvBuffer);
593         rv = SCardTransmit(hCard, &pioSendPci, bSendBuffer, send_length,
594                 &pioRecvPci, bRecvBuffer, &length);
595         printf(" card response:");
596         for (i=0; i<length; i++)
597                 printf(" %02X", bRecvBuffer[i]);
598         printf("\n");
599         PCSC_ERROR_EXIT(rv, "SCardTransmit")
600         if ((bRecvBuffer[0] != 0x90) || (bRecvBuffer[1] != 0x00))
601         {
602                 printf("Error: test applet not found!\n");
603                 goto end;
604         }
605
606 #ifdef VERIFY_PIN
607         /* verify PIN */
608         printf(" Secure verify PIN\n");
609         pin_verify = (PIN_VERIFY_STRUCTURE *)bSendBuffer;
610
611         /* PC/SC v2.02.05 Part 10 PIN verification data structure */
612         pin_verify -> bTimerOut = 0x00;
613         pin_verify -> bTimerOut2 = 0x00;
614         pin_verify -> bmFormatString = 0x82;
615         pin_verify -> bmPINBlockString = 0x08;
616         pin_verify -> bmPINLengthFormat = 0x00;
617         pin_verify -> wPINMaxExtraDigit = (PIN_min_size << 8) + PIN_max_size;
618         pin_verify -> bEntryValidationCondition = bEntryValidationCondition;
619         pin_verify -> bNumberMessage = 0x01;
620         pin_verify -> wLangId = 0x0409;         /* United States */
621         pin_verify -> bMsgIndex = 0x00;
622         pin_verify -> bTeoPrologue[0] = 0x00;
623         pin_verify -> bTeoPrologue[1] = 0x00;
624         pin_verify -> bTeoPrologue[2] = 0x00;
625         /* pin_verify -> ulDataLength = 0x00; we don't know the size yet */
626
627         /* APDU: 00 20 00 00 08 30 30 30 30 00 00 00 00 */
628         offset = 0;
629         pin_verify -> abData[offset++] = 0x00;  /* CLA */
630         pin_verify -> abData[offset++] = 0x20;  /* INS: VERIFY */
631         pin_verify -> abData[offset++] = 0x00;  /* P1 */
632         pin_verify -> abData[offset++] = 0x00;  /* P2 */
633         pin_verify -> abData[offset++] = 0x08;  /* Lc: 8 data bytes */
634         pin_verify -> abData[offset++] = 0x30;  /* '0' */
635         pin_verify -> abData[offset++] = 0x30;  /* '0' */
636         pin_verify -> abData[offset++] = 0x30;  /* '0' */
637         pin_verify -> abData[offset++] = 0x30;  /* '0' */
638         pin_verify -> abData[offset++] = 0x00;  /* '\0' */
639         pin_verify -> abData[offset++] = 0x00;  /* '\0' */
640         pin_verify -> abData[offset++] = 0x00;  /* '\0' */
641         pin_verify -> abData[offset++] = 0x00;  /* '\0' */
642         pin_verify -> ulDataLength = offset;    /* APDU size */
643
644         length = sizeof(PIN_VERIFY_STRUCTURE) + offset;
645
646         printf(" command:");
647         for (i=0; i<length; i++)
648                 printf(" %02X", bSendBuffer[i]);
649         printf("\n");
650         printf("Enter your PIN: ");
651         fflush(stdout);
652         memset(bRecvBuffer, 0xAA, sizeof bRecvBuffer);
653         rv = SCardControl(hCard, verify_ioctl, bSendBuffer,
654                 length, bRecvBuffer, sizeof(bRecvBuffer), &length);
655
656         {
657 #ifndef S_SPLINT_S
658                 fd_set fd;
659 #endif
660                 struct timeval timeout;
661
662                 FD_ZERO(&fd);
663                 FD_SET(STDIN_FILENO, &fd);      /* stdin */
664                 timeout.tv_sec = 0;                     /* timeout = 0.1s */
665                 timeout.tv_usec = 100000;
666
667                 /* we only try to read stdin if the pinpad is on a keyboard
668                  * we do not read stdin for a SPR 532 for example */
669                 if (select(1, &fd, NULL, NULL, &timeout) > 0)
670                 {
671                         /* read the fake digits */
672                         char in[40];    /* 4 digits + \n + \0 */
673                         char *s = fgets(in, sizeof(in), stdin);
674
675                         if (s)
676                                 printf("keyboard sent: %s", in);
677                 }
678                 else
679                         /* if it is not a keyboard */
680                         printf("\n");
681         }
682
683         error = FALSE;
684         if (length != 2 || bRecvBuffer[0] != 0x90 || bRecvBuffer[1] != 0x00)
685                 error = TRUE;
686
687         printf(error ? RED : GREEN);
688         printf(" card response [%"LF"d bytes]:", length);
689         for (i=0; i<length; i++)
690                 printf(" %02X", bRecvBuffer[i]);
691         printf(": %s", pinpad_return_codes(length, bRecvBuffer));
692         printf(NORMAL "\n");
693         PCSC_ERROR_CONT(rv, "SCardControl")
694
695         /* verify PIN dump */
696         printf("\nverify PIN dump:");
697         send_length = 5;
698         memcpy(bSendBuffer, "\x00\x40\x00\x00\xFF",
699                 send_length);
700         for (i=0; i<send_length; i++)
701                 printf(" %02X", bSendBuffer[i]);
702         printf("\n");
703         length = sizeof(bRecvBuffer);
704         rv = SCardTransmit(hCard, &pioSendPci, bSendBuffer, send_length,
705                 &pioRecvPci, bRecvBuffer, &length);
706         printf(" card response:");
707         for (i=0; i<length; i++)
708                 printf(" %02X", bRecvBuffer[i]);
709         printf("\n");
710         PCSC_ERROR_EXIT(rv, "SCardTransmit")
711
712         if ((2 == length) && (0x6C == bRecvBuffer[0]))
713         {
714                 printf("\nverify PIN dump:");
715                 send_length = 5;
716                 memcpy(bSendBuffer, "\x00\x40\x00\x00\xFF",
717                         send_length);
718                 bSendBuffer[4] = bRecvBuffer[1];
719                 for (i=0; i<send_length; i++)
720                         printf(" %02X", bSendBuffer[i]);
721                 printf("\n");
722                 length = sizeof(bRecvBuffer);
723                 rv = SCardTransmit(hCard, &pioSendPci, bSendBuffer, send_length,
724                         &pioRecvPci, bRecvBuffer, &length);
725                 printf(" card response:");
726                 for (i=0; i<length; i++)
727                         printf(" %02X", bRecvBuffer[i]);
728                 printf("\n");
729                 PCSC_ERROR_EXIT(rv, "SCardTransmit")
730         }
731 #endif
732
733         /* check if the reader supports Modify PIN */
734         if (0 == modify_ioctl)
735         {
736                 printf("Reader %s does not support PIN modification\n",
737                         readers[reader_nb]);
738                 goto end;
739         }
740
741 #ifdef MODIFY_PIN
742         /* Modify PIN */
743         printf(" Secure modify PIN\n");
744         pin_modify = (PIN_MODIFY_STRUCTURE *)bSendBuffer;
745
746         /* Table for bConfirmPIN and bNumberMessage
747          * bConfirmPIN = 3, bNumberMessage = 3: "Enter Pin" "New Pin" "Confirm Pin"
748          * bConfirmPIN = 2, bNumberMessage = 2: "Enter Pin" "New Pin"
749          * bConfirmPIN = 1, bNumberMessage = 2: "New Pin" "Confirm Pin"
750          * bConfirmPIN = 0, bNumberMessage = 1: "New Pin"
751          */
752         /* table for bMsgIndex[1-3]
753          * 00: PIN insertion prompt        “ENTER SMARTCARD PIN”
754          * 01: PIN Modification prompt     “ ENTER NEW PIN”
755          * 02: NEW PIN Confirmation prompt “ CONFIRM NEW PIN”
756          */
757         /* PC/SC v2.02.05 Part 10 PIN modification data structure */
758         pin_modify -> bTimerOut = 0x00;
759         pin_modify -> bTimerOut2 = 0x00;
760         pin_modify -> bmFormatString = 0x82;
761         pin_modify -> bmPINBlockString = 0x04;
762         pin_modify -> bmPINLengthFormat = 0x00;
763         pin_modify -> bInsertionOffsetOld = 0x00;       /* offset from APDU start */
764         pin_modify -> bInsertionOffsetNew = 0x04;       /* offset from APDU start */
765         pin_modify -> wPINMaxExtraDigit = (PIN_min_size << 8) + PIN_max_size;
766         pin_modify -> bConfirmPIN = 0x03;       /* b0 set = confirmation requested */
767                                                                         /* b1 set = current PIN entry requested */
768         pin_modify -> bEntryValidationCondition = bEntryValidationCondition;
769         pin_modify -> bNumberMessage = 0x03; /* see table above */
770         pin_modify -> wLangId = 0x0409;         /* United States */
771         pin_modify -> bMsgIndex1 = 0x00;
772         pin_modify -> bMsgIndex2 = 0x01;
773         pin_modify -> bMsgIndex3 = 0x02;
774         pin_modify -> bTeoPrologue[0] = 0x00;
775         pin_modify -> bTeoPrologue[1] = 0x00;
776         pin_modify -> bTeoPrologue[2] = 0x00;
777         /* pin_modify -> ulDataLength = 0x00; we don't know the size yet */
778
779         /* APDU: 00 20 00 00 08 30 30 30 30 00 00 00 00 */
780         offset = 0;
781         pin_modify -> abData[offset++] = 0x00;  /* CLA */
782         pin_modify -> abData[offset++] = 0x24;  /* INS: CHANGE/UNBLOCK */
783         pin_modify -> abData[offset++] = 0x00;  /* P1 */
784         pin_modify -> abData[offset++] = 0x00;  /* P2 */
785         pin_modify -> abData[offset++] = 0x08;  /* Lc: 2x8 data bytes */
786         pin_modify -> abData[offset++] = 0x30;  /* '0' old PIN */
787         pin_modify -> abData[offset++] = 0x30;  /* '0' */
788         pin_modify -> abData[offset++] = 0x30;  /* '0' */
789         pin_modify -> abData[offset++] = 0x30;  /* '0' */
790         pin_modify -> abData[offset++] = 0x30;  /* '0' new PIN */
791         pin_modify -> abData[offset++] = 0x30;  /* '0' */
792         pin_modify -> abData[offset++] = 0x30;  /* '0' */
793         pin_modify -> abData[offset++] = 0x30;  /* '0' */
794         pin_modify -> ulDataLength = offset;    /* APDU size */
795
796         length = sizeof(PIN_MODIFY_STRUCTURE) + offset;
797
798         printf(" command:");
799         for (i=0; i<length; i++)
800                 printf(" %02X", bSendBuffer[i]);
801         printf("\n");
802         printf("Enter your PIN: ");
803         fflush(stdout);
804         memset(bRecvBuffer, 0xAA, sizeof bRecvBuffer);
805         rv = SCardControl(hCard, modify_ioctl, bSendBuffer,
806                 length, bRecvBuffer, sizeof(bRecvBuffer), &length);
807
808         {
809 #ifndef S_SPLINT_S
810                 fd_set fd;
811 #endif
812                 struct timeval timeout;
813
814                 /* old PIN, new PIN, confirmation PIN */
815                 /* if the command is aborted we will not read every "PIN" */
816                 for (i=0; i<3; i++)
817                 {
818                         FD_ZERO(&fd);
819                         FD_SET(STDIN_FILENO, &fd);      /* stdin */
820                         timeout.tv_sec = 0;                     /* timeout = 0.1s */
821                         timeout.tv_usec = 100000;
822
823                         /* we only try to read stdin if the pinpad is on a keyboard
824                          * we do not read stdin for a SPR 532 for example */
825                         if (select(1, &fd, NULL, NULL, &timeout) > 0)
826                         {
827                                 /* read the fake digits */
828                                 char in[40];    /* 4 digits + \n + \0 */
829                                 char *ret;
830
831                                 ret = fgets(in, sizeof(in), stdin);
832                                 if (ret)
833                                         printf("keyboard sent: %s", in);
834                         }
835                         else
836                         {
837                                 /* if it is not a keyboard */
838                                 printf("\n");
839
840                                 /* exit the for() loop */
841                                 break;
842                         }
843                 }
844         }
845
846         error = FALSE;
847         if (length != 2 || bRecvBuffer[0] != 0x90 || bRecvBuffer[1] != 0x00)
848                 error = TRUE;
849
850         printf(error ? RED : GREEN);
851         printf(" card response [%"LF"d bytes]:", length);
852         for (i=0; i<length; i++)
853                 printf(" %02X", bRecvBuffer[i]);
854         printf(": %s", pinpad_return_codes(length, bRecvBuffer));
855         printf(NORMAL "\n");
856         PCSC_ERROR_CONT(rv, "SCardControl")
857
858         /* modify PIN dump */
859         printf("\nmodify PIN dump:");
860         send_length = 5;
861         memcpy(bSendBuffer, "\x00\x40\x00\x00\xFF",
862                 send_length);
863         for (i=0; i<send_length; i++)
864                 printf(" %02X", bSendBuffer[i]);
865         printf("\n");
866         length = sizeof(bRecvBuffer);
867         rv = SCardTransmit(hCard, &pioSendPci, bSendBuffer, send_length,
868                 &pioRecvPci, bRecvBuffer, &length);
869         printf(" card response:");
870         for (i=0; i<length; i++)
871                 printf(" %02X", bRecvBuffer[i]);
872         printf("\n");
873         PCSC_ERROR_EXIT(rv, "SCardTransmit")
874
875         if ((2 == length) && (0x6C == bRecvBuffer[0]))
876         {
877                 printf("\nverify PIN dump:");
878                 send_length = 5;
879                 memcpy(bSendBuffer, "\x00\x40\x00\x00\xFF",
880                         send_length);
881                 bSendBuffer[4] = bRecvBuffer[1];
882                 for (i=0; i<send_length; i++)
883                         printf(" %02X", bSendBuffer[i]);
884                 printf("\n");
885                 length = sizeof(bRecvBuffer);
886                 rv = SCardTransmit(hCard, &pioSendPci, bSendBuffer, send_length,
887                         &pioRecvPci, bRecvBuffer, &length);
888                 printf(" card response:");
889                 for (i=0; i<length; i++)
890                         printf(" %02X", bRecvBuffer[i]);
891                 printf("\n");
892                 PCSC_ERROR_EXIT(rv, "SCardTransmit")
893         }
894 #endif
895
896         /* card disconnect */
897         rv = SCardDisconnect(hCard, SCARD_UNPOWER_CARD);
898         PCSC_ERROR_CONT(rv, "SCardDisconnect")
899
900 end:
901         /* We try to leave things as clean as possible */
902         rv = SCardReleaseContext(hContext);
903         if (rv != SCARD_S_SUCCESS)
904                 printf("SCardReleaseContext: %s (0x%"LF"X)\n", pcsc_stringify_error(rv),
905                         rv);
906
907         /* free allocated memory */
908         if (mszReaders)
909                 free(mszReaders);
910         if (readers)
911                 free(readers);
912
913         return 0;
914 } /* main */
915