2 scardcontrol.c: sample code to use/test SCardControl() API
3 Copyright (C) 2004-2019 Ludovic Rousseau
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.
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.
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.
25 #include <arpa/inet.h>
27 #include <PCSC/winscard.h>
28 #include <PCSC/wintypes.h>
34 #include "PCSCv2part10.h"
38 #undef GET_GEMPC_FIRMWARE
45 #define IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE SCARD_CTL_CODE(1)
47 #define BLUE "\33[34m"
49 #define BRIGHT_RED "\33[01;31m"
50 #define GREEN "\33[32m"
51 #define NORMAL "\33[0m"
52 #define MAGENTA "\33[35m"
54 /* DWORD printf(3) format */
56 /* Apple defines DWORD as uint32_t so %d is correct */
59 /* pcsc-lite defines DWORD as unsigned long so %ld is correct */
63 /* PCSC error message pretty print */
64 #define PCSC_ERROR_EXIT(rv, text) \
65 if (rv != SCARD_S_SUCCESS) \
67 printf(text ": " RED "%s (0x%"LF"X)\n" NORMAL, pcsc_stringify_error(rv), rv); \
71 printf(text ": " BLUE "OK\n\n" NORMAL);
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); \
77 printf(text ": " BLUE "OK\n\n" NORMAL);
79 #define PRINT_GREEN(text, value) \
80 printf("%s: " GREEN "%s\n" NORMAL, text, value)
82 #define PRINT_GREEN_DEC(text, value) \
83 printf("%s: " GREEN "%d\n" NORMAL, text, value)
85 #define PRINT_RED_DEC(text, value) \
86 printf("%s: " RED "%d\n" NORMAL, text, value)
88 #define PRINT_GREEN_HEX2(text, value) \
89 printf("%s: " GREEN "0x%02X\n" NORMAL, text, value)
91 #define PRINT_GREEN_HEX4(text, value) \
92 printf("%s: " GREEN "0x%04X\n" NORMAL, text, value)
94 static void parse_properties(unsigned char *bRecvBuffer, int length)
100 while (p-bRecvBuffer < length)
113 value = *p + (*(p+1)<<8);
116 value = *p + (*(p+1)<<8) + (*(p+2)<<16) + (*(p+3)<<24);
124 case PCSCv2_PART10_PROPERTY_wLcdLayout:
125 PRINT_GREEN_HEX4(" wLcdLayout", value);
127 case PCSCv2_PART10_PROPERTY_bEntryValidationCondition:
128 PRINT_GREEN_HEX2(" bEntryValidationCondition", value);
130 case PCSCv2_PART10_PROPERTY_bTimeOut2:
131 PRINT_GREEN_HEX2(" bTimeOut2", value);
133 case PCSCv2_PART10_PROPERTY_wLcdMaxCharacters:
134 PRINT_GREEN_HEX4(" wLcdMaxCharacters", value);
136 case PCSCv2_PART10_PROPERTY_wLcdMaxLines:
137 PRINT_GREEN_HEX4(" wLcdMaxLines", value);
139 case PCSCv2_PART10_PROPERTY_bMinPINSize:
140 PRINT_GREEN_HEX2(" bMinPINSize", value);
142 case PCSCv2_PART10_PROPERTY_bMaxPINSize:
143 PRINT_GREEN_HEX2(" bMaxPINSize", value);
145 case PCSCv2_PART10_PROPERTY_sFirmwareID:
146 printf(" sFirmwareID: " GREEN);
147 for (i=0; i<len; i++)
151 case PCSCv2_PART10_PROPERTY_bPPDUSupport:
152 PRINT_GREEN_HEX2(" bPPDUSupport", value);
154 printf(" PPDU is supported over SCardControl using FEATURE_CCID_ESC_COMMAND\n");
156 printf(" PPDU is supported over SCardTransmit\n");
158 case PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize:
159 PRINT_GREEN_DEC(" dwMaxAPDUDataSize", value);
161 case PCSCv2_PART10_PROPERTY_wIdVendor:
162 PRINT_GREEN_HEX2(" wIdVendor", value);
164 case PCSCv2_PART10_PROPERTY_wIdProduct:
165 PRINT_GREEN_HEX2(" wIdProduct", value);
168 printf(" Unknown tag: 0x%02X (length = %d)\n", tag, len);
173 } /* parse_properties */
176 static const char *pinpad_return_codes(int length,
177 unsigned char bRecvBuffer[])
179 const char * ret = "UNKNOWN";
184 if ((0x90 == bRecvBuffer[0]) && (0x00 == bRecvBuffer[1]))
187 if (0x64 == bRecvBuffer[0])
189 switch (bRecvBuffer[1])
196 ret = "Cancelled by user";
200 ret = "PIN mismatch";
204 ret = "Too short or too long PIN";
212 int main(int argc, char *argv[])
215 SCARDCONTEXT hContext;
217 LPSTR mszReaders = NULL;
218 char *ptr, **readers = NULL;
221 DWORD dwActiveProtocol, dwReaderLen, dwState, dwProt, dwAtrLen;
222 BYTE pbAtr[MAX_ATR_SIZE] = "";
223 char pbReader[MAX_READERNAME] = "";
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)
242 PIN_VERIFY_STRUCTURE *pin_verify;
245 PIN_MODIFY_STRUCTURE *pin_modify;
248 int PIN_min_size = 4;
249 int PIN_max_size = 8;
251 /* table for bEntryValidationCondition
252 * 0x01: Max size reached
253 * 0x02: Validation key pressed
254 * 0x04: Timeout occurred
256 int bEntryValidationCondition = 7;
258 printf("SCardControl sample code\n");
259 printf("V 1.4 © 2004-2010, Ludovic Rousseau <ludovic.rousseau@free.fr>\n\n");
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);
264 rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
265 if (rv != SCARD_S_SUCCESS)
267 printf("SCardEstablishContext: Cannot Connect to Resource Manager %"LF"X\n", rv);
271 /* Retrieve the available readers list */
272 rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
273 PCSC_ERROR_EXIT(rv, "SCardListReaders")
275 mszReaders = malloc(sizeof(char)*dwReaders);
276 if (mszReaders == NULL)
278 printf("malloc: not enough memory\n");
282 rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
283 if (rv != SCARD_S_SUCCESS)
284 printf("SCardListReader: %"LF"X\n", rv);
286 /* Extract readers from the null separated string and get the total
287 * number of readers */
292 ptr += strlen(ptr)+1;
298 printf("No reader found\n");
302 /* allocate the readers table */
303 readers = calloc(nbReaders, sizeof(char *));
306 printf("Not enough memory for readers[]\n");
310 /* fill the readers table */
313 printf("Available readers (use command line argument to select)\n");
316 printf("%d: %s\n", nbReaders, ptr);
317 readers[nbReaders] = ptr;
318 ptr += strlen(ptr)+1;
325 reader_nb = atoi(argv[1]);
326 if (reader_nb < 0 || reader_nb >= nbReaders)
328 printf("Wrong reader index: %d\n", reader_nb);
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")
343 #ifdef GET_GEMPC_FIRMWARE
344 /* get GemPC firmware */
345 printf(" Get GemPC Firmware\n");
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);
352 printf(" Firmware: " GREEN);
353 for (i=0; i<length; i++)
354 printf("%02X ", bRecvBuffer[i]);
357 bRecvBuffer[length] = '\0';
358 printf(" Firmware: " GREEN "%s" NORMAL" (length " GREEN "%ld" NORMAL " bytes)\n", bRecvBuffer, length);
360 PCSC_ERROR_CONT(rv, "SCardControl")
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")
368 printf(" TLV (%"LF"d): " GREEN, length);
369 for (i=0; i<length; i++)
370 printf("%02X ", bRecvBuffer[i]);
373 PCSC_ERROR_CONT(rv, "SCardControl(CM_IOCTL_GET_FEATURE_REQUEST)")
375 if (length % sizeof(PCSC_TLV_STRUCTURE))
377 printf("Inconsistent result! Bad TLV values!\n");
381 /* get the number of elements instead of the complete size */
382 length /= sizeof(PCSC_TLV_STRUCTURE);
384 pcsc_tlv = (PCSC_TLV_STRUCTURE *)bRecvBuffer;
385 for (i = 0; i < length; i++)
387 switch (pcsc_tlv[i].tag)
389 case FEATURE_VERIFY_PIN_DIRECT:
390 PRINT_GREEN("Reader supports", "FEATURE_VERIFY_PIN_DIRECT");
391 verify_ioctl = ntohl(pcsc_tlv[i].value);
393 case FEATURE_MODIFY_PIN_DIRECT:
394 PRINT_GREEN("Reader supports", "FEATURE_MODIFY_PIN_DIRECT");
395 modify_ioctl = ntohl(pcsc_tlv[i].value);
397 case FEATURE_IFD_PIN_PROPERTIES:
398 PRINT_GREEN("Reader supports", "FEATURE_IFD_PIN_PROPERTIES");
399 pin_properties_ioctl = ntohl(pcsc_tlv[i].value);
401 case FEATURE_MCT_READER_DIRECT:
402 PRINT_GREEN("Reader supports", "FEATURE_MCT_READER_DIRECT");
403 mct_readerdirect_ioctl = ntohl(pcsc_tlv[i].value);
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);
409 case FEATURE_CCID_ESC_COMMAND:
410 PRINT_GREEN("Reader supports", "FEATURE_CCID_ESC_COMMAND");
411 ccid_esc_command = ntohl(pcsc_tlv[i].value);
414 PRINT_RED_DEC("Can't parse tag", pcsc_tlv[i].tag);
419 if (properties_in_tlv_ioctl)
424 rv = SCardControl(hCard, properties_in_tlv_ioctl, NULL, 0,
425 bRecvBuffer, sizeof(bRecvBuffer), &length);
426 PCSC_ERROR_CONT(rv, "SCardControl(GET_TLV_PROPERTIES)")
428 printf("GET_TLV_PROPERTIES (" GREEN "%"LF"d" NORMAL "): " GREEN, length);
429 for (i=0; i<length; i++)
430 printf("%02X ", bRecvBuffer[i]);
433 printf("\nDisplay all the properties:\n");
434 parse_properties(bRecvBuffer, length);
436 printf("\nFind a specific property:\n");
437 ret = PCSCv2Part10_find_TLV_property_by_tag_from_buffer(bRecvBuffer, length, PCSCv2_PART10_PROPERTY_wIdVendor, &value);
439 PRINT_RED_DEC(" wIdVendor", ret);
441 PRINT_GREEN_HEX4(" wIdVendor", value);
443 ret = PCSCv2Part10_find_TLV_property_by_tag_from_hcard(hCard, PCSCv2_PART10_PROPERTY_wIdProduct, &value);
445 PRINT_RED_DEC(" wIdProduct", ret);
447 PRINT_GREEN_HEX4(" wIdProduct", value);
449 ret = PCSCv2Part10_find_TLV_property_by_tag_from_hcard(hCard, PCSCv2_PART10_PROPERTY_bMinPINSize, &value);
452 PIN_min_size = value;
453 PRINT_GREEN_DEC(" PIN min size defined", PIN_min_size);
457 ret = PCSCv2Part10_find_TLV_property_by_tag_from_hcard(hCard, PCSCv2_PART10_PROPERTY_bMaxPINSize, &value);
460 PIN_max_size = value;
461 PRINT_GREEN_DEC(" PIN max size defined", PIN_max_size);
464 ret = PCSCv2Part10_find_TLV_property_by_tag_from_hcard(hCard, PCSCv2_PART10_PROPERTY_bEntryValidationCondition, &value);
467 bEntryValidationCondition = value;
468 PRINT_GREEN_DEC(" Entry Validation Condition defined",
469 bEntryValidationCondition);
475 if (mct_readerdirect_ioctl)
477 char secoder_info[] = { 0x20, 0x70, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 };
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)")
483 printf("MCT_READER_DIRECT (%"LF"d): ", length);
484 for (i=0; i<length; i++)
485 printf("%02X ", bRecvBuffer[i]);
489 if (pin_properties_ioctl)
491 PIN_PROPERTIES_STRUCTURE *pin_properties;
493 rv = SCardControl(hCard, pin_properties_ioctl, NULL, 0,
494 bRecvBuffer, sizeof(bRecvBuffer), &length);
495 PCSC_ERROR_CONT(rv, "SCardControl(pin_properties_ioctl)")
497 printf("PIN PROPERTIES (" GREEN "%"LF"d" NORMAL "): " GREEN, length);
498 for (i=0; i<length; i++)
499 printf("%02X ", bRecvBuffer[i]);
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);
511 #ifdef GET_GEMPC_FIRMWARE
512 if (ccid_esc_command)
514 /* get GemPC firmware */
515 printf("Get GemPC Firmware\n");
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);
522 printf(" Firmware: " GREEN);
523 for (i=0; i<length; i++)
524 printf("%02X ", bRecvBuffer[i]);
527 bRecvBuffer[length] = '\0';
528 printf(" Firmware: " GREEN "%s" NORMAL" (length " GREEN "%ld" NORMAL " bytes)\n", bRecvBuffer, length);
530 PCSC_ERROR_CONT(rv, "SCardControl")
533 (void)ccid_esc_command;
536 if (0 == verify_ioctl)
538 printf("Reader %s does not support PIN verification\n",
543 /* get card status */
544 dwAtrLen = sizeof(pbAtr);
545 dwReaderLen = sizeof(pbReader);
546 rv = SCardStatus(hCard, pbReader, &dwReaderLen, &dwState, &dwProt,
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]);
555 PCSC_ERROR_CONT(rv, "SCardStatus")
557 if (dwState & SCARD_ABSENT)
559 printf("No card inserted\n");
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,
568 printf(" Protocol: %"LF"d\n", dwActiveProtocol);
569 PCSC_ERROR_EXIT(rv, "SCardReconnect")
571 switch(dwActiveProtocol)
573 case SCARD_PROTOCOL_T0:
574 pioSendPci = *SCARD_PCI_T0;
576 case SCARD_PROTOCOL_T1:
577 pioSendPci = *SCARD_PCI_T1;
580 printf("Unknown protocol. No card present?\n");
584 /* APDU select applet */
585 printf("Select applet:");
587 memcpy(bSendBuffer, "\x00\xA4\x04\x00\x06\xA0\x00\x00\x00\x18\xFF",
589 for (i=0; i<send_length; i++)
590 printf(" %02X", bSendBuffer[i]);
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]);
599 PCSC_ERROR_EXIT(rv, "SCardTransmit")
600 if ((bRecvBuffer[0] != 0x90) || (bRecvBuffer[1] != 0x00))
602 printf("Error: test applet not found!\n");
608 printf(" Secure verify PIN\n");
609 pin_verify = (PIN_VERIFY_STRUCTURE *)bSendBuffer;
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 */
627 /* APDU: 00 20 00 00 08 30 30 30 30 00 00 00 00 */
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 */
644 length = sizeof(PIN_VERIFY_STRUCTURE) + offset;
647 for (i=0; i<length; i++)
648 printf(" %02X", bSendBuffer[i]);
650 printf("Enter your PIN: ");
652 memset(bRecvBuffer, 0xAA, sizeof bRecvBuffer);
653 rv = SCardControl(hCard, verify_ioctl, bSendBuffer,
654 length, bRecvBuffer, sizeof(bRecvBuffer), &length);
660 struct timeval timeout;
663 FD_SET(STDIN_FILENO, &fd); /* stdin */
664 timeout.tv_sec = 0; /* timeout = 0.1s */
665 timeout.tv_usec = 100000;
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)
671 /* read the fake digits */
672 char in[40]; /* 4 digits + \n + \0 */
673 char *s = fgets(in, sizeof(in), stdin);
676 printf("keyboard sent: %s", in);
679 /* if it is not a keyboard */
684 if (length != 2 || bRecvBuffer[0] != 0x90 || bRecvBuffer[1] != 0x00)
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));
693 PCSC_ERROR_CONT(rv, "SCardControl")
695 /* verify PIN dump */
696 printf("\nverify PIN dump:");
698 memcpy(bSendBuffer, "\x00\x40\x00\x00\xFF",
700 for (i=0; i<send_length; i++)
701 printf(" %02X", bSendBuffer[i]);
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]);
710 PCSC_ERROR_EXIT(rv, "SCardTransmit")
712 if ((2 == length) && (0x6C == bRecvBuffer[0]))
714 printf("\nverify PIN dump:");
716 memcpy(bSendBuffer, "\x00\x40\x00\x00\xFF",
718 bSendBuffer[4] = bRecvBuffer[1];
719 for (i=0; i<send_length; i++)
720 printf(" %02X", bSendBuffer[i]);
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]);
729 PCSC_ERROR_EXIT(rv, "SCardTransmit")
733 /* check if the reader supports Modify PIN */
734 if (0 == modify_ioctl)
736 printf("Reader %s does not support PIN modification\n",
743 printf(" Secure modify PIN\n");
744 pin_modify = (PIN_MODIFY_STRUCTURE *)bSendBuffer;
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"
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”
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 */
779 /* APDU: 00 20 00 00 08 30 30 30 30 00 00 00 00 */
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 */
796 length = sizeof(PIN_MODIFY_STRUCTURE) + offset;
799 for (i=0; i<length; i++)
800 printf(" %02X", bSendBuffer[i]);
802 printf("Enter your PIN: ");
804 memset(bRecvBuffer, 0xAA, sizeof bRecvBuffer);
805 rv = SCardControl(hCard, modify_ioctl, bSendBuffer,
806 length, bRecvBuffer, sizeof(bRecvBuffer), &length);
812 struct timeval timeout;
814 /* old PIN, new PIN, confirmation PIN */
815 /* if the command is aborted we will not read every "PIN" */
819 FD_SET(STDIN_FILENO, &fd); /* stdin */
820 timeout.tv_sec = 0; /* timeout = 0.1s */
821 timeout.tv_usec = 100000;
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)
827 /* read the fake digits */
828 char in[40]; /* 4 digits + \n + \0 */
831 ret = fgets(in, sizeof(in), stdin);
833 printf("keyboard sent: %s", in);
837 /* if it is not a keyboard */
840 /* exit the for() loop */
847 if (length != 2 || bRecvBuffer[0] != 0x90 || bRecvBuffer[1] != 0x00)
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));
856 PCSC_ERROR_CONT(rv, "SCardControl")
858 /* modify PIN dump */
859 printf("\nmodify PIN dump:");
861 memcpy(bSendBuffer, "\x00\x40\x00\x00\xFF",
863 for (i=0; i<send_length; i++)
864 printf(" %02X", bSendBuffer[i]);
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]);
873 PCSC_ERROR_EXIT(rv, "SCardTransmit")
875 if ((2 == length) && (0x6C == bRecvBuffer[0]))
877 printf("\nverify PIN dump:");
879 memcpy(bSendBuffer, "\x00\x40\x00\x00\xFF",
881 bSendBuffer[4] = bRecvBuffer[1];
882 for (i=0; i<send_length; i++)
883 printf(" %02X", bSendBuffer[i]);
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]);
892 PCSC_ERROR_EXIT(rv, "SCardTransmit")
896 /* card disconnect */
897 rv = SCardDisconnect(hCard, SCARD_UNPOWER_CARD);
898 PCSC_ERROR_CONT(rv, "SCardDisconnect")
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),
907 /* free allocated memory */