int main(void) { unsigned char cmd1[] = { 0x00, 0xa4, 0x04, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x63, 0x86, 0x53, 0x49, 0x44, 0x01}; unsigned char cmd2[] = { 0x80, 0x56, 0x00, 0x00, 0x04 }; unsigned char cmd3[] = { 0x80, 0x48, 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff }; unsigned char cmd4[] = { 0x80, 0x44, 0x00, 0x00, 0x05}; LONG rv; SCARDCONTEXT hContext; DWORD dwReaders; LPSTR mszReaders = NULL; char **readers = NULL; SCARDHANDLE hCard; DWORD dwActiveProtocol; unsigned char bRecvBuffer[MAX_BUFFER_SIZE]; DWORD length; SCARD_IO_REQUEST pioRecvPci; SCARD_IO_REQUEST pioSendPci; rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); if (rv != SCARD_S_SUCCESS) { printf("SCardEstablishContext: Cannot Connect to Resource Manager %"LF"X\n", rv); return 1; } /* Retrieve the available readers list */ rv = SCardListReaders(hContext, NULL, NULL, &dwReaders); PCSC_ERROR_EXIT(rv, "SCardListReader"); if (dwReaders < 4) { printf("No reader found!\n"); return -1; } mszReaders = malloc(sizeof(char)*dwReaders); if (mszReaders == NULL) { printf("malloc: not enough memory\n"); goto end; } rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders); PCSC_ERROR_EXIT(rv, "SCardListReader"); /* connect to the first reader */ dwActiveProtocol = -1; rv = SCardConnect(hContext, mszReaders, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol); PCSC_ERROR_EXIT(rv, "SCardConnect") switch(dwActiveProtocol) { case SCARD_PROTOCOL_T0: pioSendPci = *SCARD_PCI_T0; break; case SCARD_PROTOCOL_T1: pioSendPci = *SCARD_PCI_T1; break; default: printf("Unknown protocol\n"); return -1; } /* APDU select applet */ length = sizeof(bRecvBuffer); rv = SCardTransmit(hCard, &pioSendPci, cmd1, sizeof cmd1, &pioRecvPci, bRecvBuffer, &length); PCSC_ERROR_EXIT(rv, "SCardTransmit") if ((length != 2) || (bRecvBuffer[0] != 0x90) || (bRecvBuffer[1] != 0x00)) { printf("cmd1 failed (%"LF"d): %02X%02X\n", length, bRecvBuffer[length-2], bRecvBuffer[length-1]); goto end; } /* non ISO APDU */ length = sizeof(bRecvBuffer); rv = SCardTransmit(hCard, &pioSendPci, cmd2, sizeof cmd2, &pioRecvPci, bRecvBuffer, &length); PCSC_ERROR_EXIT(rv, "SCardTransmit") if ((length != 6) || (bRecvBuffer[4] != 0x90) || (bRecvBuffer[5] != 0x00)) { printf("cmd2 failed (%"LF"d) : %02X%02X\n", length, bRecvBuffer[length-2], bRecvBuffer[length-1]); goto end; } /* get the argument for cmd3 from result of cmd2 */ memcpy(cmd3+5, bRecvBuffer, 4); /* non ISO APDU */ length = sizeof(bRecvBuffer); rv = SCardTransmit(hCard, &pioSendPci, cmd3, sizeof cmd3, &pioRecvPci, bRecvBuffer, &length); PCSC_ERROR_EXIT(rv, "SCardTransmit") if ((length != 2) || (bRecvBuffer[0] != 0x90) || (bRecvBuffer[1] != 0x00)) { printf("cmd3 failed (%"LF"d): %02X%02X\n", length, bRecvBuffer[length-2], bRecvBuffer[length-1]); goto end; } /* non iSO APDU */ length = sizeof(bRecvBuffer); rv = SCardTransmit(hCard, &pioSendPci, cmd4, sizeof cmd4, &pioRecvPci, bRecvBuffer, &length); PCSC_ERROR_EXIT(rv, "SCardTransmit") if ((length != 7) || (bRecvBuffer[5] != 0x90) || (bRecvBuffer[6] != 0x00)) { printf("cmd4 failed (%"LF"d): %02X%02X\n", length, bRecvBuffer[length-2], bRecvBuffer[length-1]); goto end; } printf("%02X%02X%02X\n", bRecvBuffer[2], bRecvBuffer[3], bRecvBuffer[4]); end: /* We try to leave things as clean as possible */ rv = SCardReleaseContext(hContext); if (rv != SCARD_S_SUCCESS) printf("SCardReleaseContext: %s (0x%"LF"X)\n", pcsc_stringify_error(rv), rv); /* free allocated memory */ free(mszReaders); free(readers); return 0; } /* main */
int main(int argc, char *argv[]) { LONG rv; SCARDCONTEXT hContext; DWORD dwReaders; LPSTR mszReaders = NULL; char *ptr, **readers = NULL; int nbReaders; SCARDHANDLE hCard; DWORD dwActiveProtocol, dwReaderLen, dwState, dwProt, dwAtrLen; BYTE pbAtr[MAX_ATR_SIZE] = ""; char pbReader[MAX_READERNAME] = ""; int reader_nb; unsigned int i; unsigned char bSendBuffer[MAX_BUFFER_SIZE]; unsigned char bRecvBuffer[MAX_BUFFER_SIZE]; DWORD send_length, length; DWORD verify_ioctl = 0; DWORD modify_ioctl = 0; DWORD pin_properties_ioctl = 0; DWORD mct_readerdirect_ioctl = 0; DWORD properties_in_tlv_ioctl = 0; DWORD ccid_esc_command = 0; SCARD_IO_REQUEST pioRecvPci; SCARD_IO_REQUEST pioSendPci; PCSC_TLV_STRUCTURE *pcsc_tlv; #if defined(VERIFY_PIN) | defined(MODIFY_PIN) int offset; #endif #ifdef VERIFY_PIN PIN_VERIFY_STRUCTURE *pin_verify; #endif #ifdef MODIFY_PIN PIN_MODIFY_STRUCTURE *pin_modify; #endif printf("SCardControl sample code\n"); printf("V 1.4 © 2004-2010, Ludovic Rousseau <*****@*****.**>\n\n"); printf(MAGENTA "THIS PROGRAM IS NOT DESIGNED AS A TESTING TOOL!\n"); printf("Do NOT use it unless you really know what you do.\n\n" NORMAL); rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); if (rv != SCARD_S_SUCCESS) { printf("SCardEstablishContext: Cannot Connect to Resource Manager %ulX\n", rv); return 1; } /* Retrieve the available readers list */ rv = SCardListReaders(hContext, NULL, NULL, &dwReaders); PCSC_ERROR_EXIT(rv, "SCardListReaders") mszReaders = malloc(sizeof(char)*dwReaders); if (mszReaders == NULL) { printf("malloc: not enough memory\n"); goto end; } rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders); if (rv != SCARD_S_SUCCESS) printf("SCardListReader: %ulX\n", rv); /* Extract readers from the null separated string and get the total * number of readers */ nbReaders = 0; ptr = mszReaders; while (*ptr != '\0') { ptr += strlen(ptr)+1; nbReaders++; } if (nbReaders == 0) { printf("No reader found\n"); goto end; } /* allocate the readers table */ readers = calloc(nbReaders, sizeof(char *)); if (NULL == readers) { printf("Not enough memory for readers[]\n"); goto end; } /* fill the readers table */ nbReaders = 0; ptr = mszReaders; printf("Available readers (use command line argument to select)\n"); while (*ptr != '\0') { printf("%d: %s\n", nbReaders, ptr); readers[nbReaders] = ptr; ptr += strlen(ptr)+1; nbReaders++; } printf("\n"); if (argc > 1) { reader_nb = atoi(argv[1]); if (reader_nb < 0 || reader_nb >= nbReaders) { printf("Wrong reader index: %d\n", reader_nb); goto end; } } else reader_nb = 0; /* connect to a reader (even without a card) */ dwActiveProtocol = -1; printf("Using reader: " GREEN "%s\n" NORMAL, readers[reader_nb]); rv = SCardConnect(hContext, readers[reader_nb], SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol); printf(" Protocol: " GREEN "%uld\n" NORMAL, dwActiveProtocol); PCSC_ERROR_EXIT(rv, "SCardConnect") #ifdef GET_GEMPC_FIRMWARE /* get GemPC firmware */ printf(" Get GemPC Firmware\n"); /* this is specific to Gemalto readers */ bSendBuffer[0] = 0x02; rv = SCardControl(hCard, IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE, bSendBuffer, 1, bRecvBuffer, sizeof(bRecvBuffer), &length); printf(" Firmware: " GREEN); for (i=0; i<length; i++) printf("%02X ", bRecvBuffer[i]); printf(NORMAL "\n"); bRecvBuffer[length] = '\0'; printf(" Firmware: " GREEN "%s" NORMAL" (length " GREEN "%ld" NORMAL " bytes)\n", bRecvBuffer, length); PCSC_ERROR_CONT(rv, "SCardControl") #endif /* does the reader support PIN verification? */ rv = SCardControl(hCard, CM_IOCTL_GET_FEATURE_REQUEST, NULL, 0, bRecvBuffer, sizeof(bRecvBuffer), &length); PCSC_ERROR_EXIT(rv, "SCardControl") printf(" TLV (%uld): " GREEN, length); for (i=0; i<length; i++) printf("%02X ", bRecvBuffer[i]); printf(NORMAL "\n"); PCSC_ERROR_CONT(rv, "SCardControl(CM_IOCTL_GET_FEATURE_REQUEST)") if (length % sizeof(PCSC_TLV_STRUCTURE)) { printf("Inconsistent result! Bad TLV values!\n"); goto end; } /* get the number of elements instead of the complete size */ length /= sizeof(PCSC_TLV_STRUCTURE); pcsc_tlv = (PCSC_TLV_STRUCTURE *)bRecvBuffer; for (i = 0; i < length; i++) { switch (pcsc_tlv[i].tag) { case FEATURE_VERIFY_PIN_DIRECT: PRINT_GREEN("Reader supports", "FEATURE_VERIFY_PIN_DIRECT"); verify_ioctl = ntohl(pcsc_tlv[i].value); break; case FEATURE_MODIFY_PIN_DIRECT: PRINT_GREEN("Reader supports", "FEATURE_MODIFY_PIN_DIRECT"); modify_ioctl = ntohl(pcsc_tlv[i].value); break; case FEATURE_IFD_PIN_PROPERTIES: PRINT_GREEN("Reader supports", "FEATURE_IFD_PIN_PROPERTIES"); pin_properties_ioctl = ntohl(pcsc_tlv[i].value); break; case FEATURE_MCT_READER_DIRECT: PRINT_GREEN("Reader supports", "FEATURE_MCT_READER_DIRECT"); mct_readerdirect_ioctl = ntohl(pcsc_tlv[i].value); break; case FEATURE_GET_TLV_PROPERTIES: PRINT_GREEN("Reader supports", "FEATURE_GET_TLV_PROPERTIES"); properties_in_tlv_ioctl = ntohl(pcsc_tlv[i].value); break; case FEATURE_CCID_ESC_COMMAND: PRINT_GREEN("Reader supports", "FEATURE_CCID_ESC_COMMAND"); ccid_esc_command = ntohl(pcsc_tlv[i].value); break; default: PRINT_RED_DEC("Can't parse tag", pcsc_tlv[i].tag); } } printf("\n"); if (properties_in_tlv_ioctl) { int value; int ret; rv = SCardControl(hCard, properties_in_tlv_ioctl, NULL, 0, bRecvBuffer, sizeof(bRecvBuffer), &length); PCSC_ERROR_CONT(rv, "SCardControl(GET_TLV_PROPERTIES)") printf("GET_TLV_PROPERTIES (" GREEN "%uld" NORMAL "): " GREEN, length); for (i=0; i<length; i++) printf("%02X ", bRecvBuffer[i]); printf(NORMAL "\n"); printf("\nDisplay all the properties:\n"); parse_properties(bRecvBuffer, length); printf("\nFind a specific property:\n"); ret = PCSCv2Part10_find_TLV_property_by_tag_from_buffer(bRecvBuffer, length, PCSCv2_PART10_PROPERTY_wIdVendor, &value); if (ret) PRINT_RED_DEC(" wIdVendor", ret); else PRINT_GREEN_HEX4(" wIdVendor", value); ret = PCSCv2Part10_find_TLV_property_by_tag_from_hcard(hCard, PCSCv2_PART10_PROPERTY_wIdProduct, &value); if (ret) PRINT_RED_DEC(" wIdProduct", ret); else PRINT_GREEN_HEX4(" wIdProduct", value); printf("\n"); } if (mct_readerdirect_ioctl) { char secoder_info[] = { 0x20, 0x70, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 }; rv = SCardControl(hCard, mct_readerdirect_ioctl, secoder_info, sizeof(secoder_info), bRecvBuffer, sizeof(bRecvBuffer), &length); PCSC_ERROR_CONT(rv, "SCardControl(MCT_READER_DIRECT)") printf("MCT_READER_DIRECT (%uld): ", length); for (i=0; i<length; i++) printf("%02X ", bRecvBuffer[i]); printf("\n"); } if (pin_properties_ioctl) { PIN_PROPERTIES_STRUCTURE *pin_properties; rv = SCardControl(hCard, pin_properties_ioctl, NULL, 0, bRecvBuffer, sizeof(bRecvBuffer), &length); PCSC_ERROR_CONT(rv, "SCardControl(pin_properties_ioctl)") printf("PIN PROPERTIES (" GREEN "%uld" NORMAL "): " GREEN, length); for (i=0; i<length; i++) printf("%02X ", bRecvBuffer[i]); printf(NORMAL "\n"); pin_properties = (PIN_PROPERTIES_STRUCTURE *)bRecvBuffer; PRINT_GREEN_HEX4(" wLcdLayout", pin_properties -> wLcdLayout); PRINT_GREEN_DEC(" bEntryValidationCondition", pin_properties -> bEntryValidationCondition); PRINT_GREEN_DEC(" bTimeOut2", pin_properties -> bTimeOut2); printf("\n"); } #ifdef GET_GEMPC_FIRMWARE if (ccid_esc_command) { /* get GemPC firmware */ printf("Get GemPC Firmware\n"); /* this is specific to Gemalto readers */ bSendBuffer[0] = 0x02; rv = SCardControl(hCard, ccid_esc_command, bSendBuffer, 1, bRecvBuffer, sizeof(bRecvBuffer), &length); printf(" Firmware: " GREEN); for (i=0; i<length; i++) printf("%02X ", bRecvBuffer[i]); printf(NORMAL "\n"); bRecvBuffer[length] = '\0'; printf(" Firmware: " GREEN "%s" NORMAL" (length " GREEN "%ld" NORMAL " bytes)\n", bRecvBuffer, length); PCSC_ERROR_CONT(rv, "SCardControl") } #endif if (0 == verify_ioctl) { printf("Reader %s does not support PIN verification\n", readers[reader_nb]); goto end; } /* get card status */ dwAtrLen = sizeof(pbAtr); dwReaderLen = sizeof(pbReader); rv = SCardStatus(hCard, pbReader, &dwReaderLen, &dwState, &dwProt, pbAtr, &dwAtrLen); printf(" Reader: %s (length %uld bytes)\n", pbReader, dwReaderLen); printf(" State: 0x%04ulX\n", dwState); printf(" Prot: %uld\n", dwProt); printf(" ATR (length %uld bytes):", dwAtrLen); for (i=0; i<dwAtrLen; i++) printf(" %02X", pbAtr[i]); printf("\n"); PCSC_ERROR_CONT(rv, "SCardStatus") if (dwState & SCARD_ABSENT) { printf("No card inserted\n"); goto end; } /* connect to a reader (even without a card) */ dwActiveProtocol = -1; rv = SCardReconnect(hCard, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1, SCARD_LEAVE_CARD, &dwActiveProtocol); printf(" Protocol: %uld\n", dwActiveProtocol); PCSC_ERROR_EXIT(rv, "SCardReconnect") switch(dwActiveProtocol) { case SCARD_PROTOCOL_T0: pioSendPci = *SCARD_PCI_T0; break; case SCARD_PROTOCOL_T1: pioSendPci = *SCARD_PCI_T1; break; default: printf("Unknown protocol. No card present?\n"); return -1; } /* APDU select applet */ printf("Select applet: "); send_length = 11; memcpy(bSendBuffer, "\x00\xA4\x04\x00\x06\xA0\x00\x00\x00\x18\xFF", send_length); for (i=0; i<send_length; i++) printf(" %02X", bSendBuffer[i]); printf("\n"); length = sizeof(bRecvBuffer); rv = SCardTransmit(hCard, &pioSendPci, bSendBuffer, send_length, &pioRecvPci, bRecvBuffer, &length); printf(" card response:"); for (i=0; i<length; i++) printf(" %02X", bRecvBuffer[i]); printf("\n"); PCSC_ERROR_EXIT(rv, "SCardTransmit") if ((bRecvBuffer[0] != 0x90) || (bRecvBuffer[1] != 0x00)) { printf("Error: test applet not found!\n"); goto end; } #ifdef VERIFY_PIN /* verify PIN */ printf(" Secure verify PIN\n"); pin_verify = (PIN_VERIFY_STRUCTURE *)bSendBuffer; /* table for bEntryValidationCondition * 0x01: Max size reached * 0x02: Validation key pressed * 0x04: Timeout occured */ /* PC/SC v2.02.05 Part 10 PIN verification data structure */ pin_verify -> bTimerOut = 0x00; pin_verify -> bTimerOut2 = 0x00; pin_verify -> bmFormatString = 0x82; pin_verify -> bmPINBlockString = 0x04; pin_verify -> bmPINLengthFormat = 0x00; pin_verify -> wPINMaxExtraDigit = 0x0408; /* Min Max */ pin_verify -> bEntryValidationCondition = 0x02; /* validation key pressed */ pin_verify -> bNumberMessage = 0x01; pin_verify -> wLangId = 0x0904; pin_verify -> bMsgIndex = 0x00; pin_verify -> bTeoPrologue[0] = 0x00; pin_verify -> bTeoPrologue[1] = 0x00; pin_verify -> bTeoPrologue[2] = 0x00; /* pin_verify -> ulDataLength = 0x00; we don't know the size yet */ /* APDU: 00 20 00 00 08 30 30 30 30 00 00 00 00 */ offset = 0; pin_verify -> abData[offset++] = 0x00; /* CLA */ pin_verify -> abData[offset++] = 0x20; /* INS: VERIFY */ pin_verify -> abData[offset++] = 0x00; /* P1 */ pin_verify -> abData[offset++] = 0x00; /* P2 */ pin_verify -> abData[offset++] = 0x08; /* Lc: 8 data bytes */ pin_verify -> abData[offset++] = 0x30; /* '0' */ pin_verify -> abData[offset++] = 0x30; /* '0' */ pin_verify -> abData[offset++] = 0x30; /* '0' */ pin_verify -> abData[offset++] = 0x30; /* '0' */ pin_verify -> abData[offset++] = 0x00; /* '\0' */ pin_verify -> abData[offset++] = 0x00; /* '\0' */ pin_verify -> abData[offset++] = 0x00; /* '\0' */ pin_verify -> abData[offset++] = 0x00; /* '\0' */ pin_verify -> ulDataLength = offset; /* APDU size */ length = sizeof(PIN_VERIFY_STRUCTURE) + offset -1; /* -1 because PIN_VERIFY_STRUCTURE contains the first byte of abData[] */ printf(" command:"); for (i=0; i<length; i++) printf(" %02X", bSendBuffer[i]); printf("\n"); printf("Enter your PIN: "); fflush(stdout); rv = SCardControl(hCard, verify_ioctl, bSendBuffer, length, bRecvBuffer, sizeof(bRecvBuffer), &length); { #ifndef S_SPLINT_S fd_set fd; #endif struct timeval timeout; FD_ZERO(&fd); FD_SET(STDIN_FILENO, &fd); /* stdin */ timeout.tv_sec = 0; /* timeout = 0.1s */ timeout.tv_usec = 100000; /* we only try to read stdin if the pinpad is on a keyboard * we do not read stdin for a SPR 532 for example */ if (select(1, &fd, NULL, NULL, &timeout) > 0) { /* read the fake digits */ char in[40]; /* 4 digits + \n + \0 */ (void)fgets(in, sizeof(in), stdin); printf("keyboard sent: %s", in); } else /* if it is not a keyboard */ printf("\n"); } printf(" card response:"); for (i=0; i<length; i++) printf(" %02X", bRecvBuffer[i]); printf("\n"); PCSC_ERROR_CONT(rv, "SCardControl") /* verify PIN dump */ printf("\nverify PIN dump: "); send_length = 5; memcpy(bSendBuffer, "\x00\x40\x00\x00\xFF", send_length); for (i=0; i<send_length; i++) printf(" %02X", bSendBuffer[i]); printf("\n"); length = sizeof(bRecvBuffer); rv = SCardTransmit(hCard, &pioSendPci, bSendBuffer, send_length, &pioRecvPci, bRecvBuffer, &length); printf(" card response:"); for (i=0; i<length; i++) printf(" %02X", bRecvBuffer[i]); printf("\n"); PCSC_ERROR_EXIT(rv, "SCardTransmit") if ((2 == length) && (0x6C == bRecvBuffer[0])) { printf("\nverify PIN dump: "); send_length = 5; memcpy(bSendBuffer, "\x00\x40\x00\x00\xFF", send_length); bSendBuffer[4] = bRecvBuffer[1]; for (i=0; i<send_length; i++) printf(" %02X", bSendBuffer[i]); printf("\n"); length = sizeof(bRecvBuffer); rv = SCardTransmit(hCard, &pioSendPci, bSendBuffer, send_length, &pioRecvPci, bRecvBuffer, &length); printf(" card response:"); for (i=0; i<length; i++) printf(" %02X", bRecvBuffer[i]); printf("\n"); PCSC_ERROR_EXIT(rv, "SCardTransmit") }
int CheckReader(EFI_SMART_CARD_READER_PROTOCOL *SmartCardReader) { EFI_STATUS rv; unsigned int i; unsigned char bSendBuffer[MAX_BUFFER_SIZE]; unsigned char bRecvBuffer[MAX_BUFFER_SIZE]; int send_length; UINTN length; int verify_ioctl = 0; int modify_ioctl = 0; int pin_properties_ioctl = 0; int mct_readerdirect_ioctl = 0; int properties_in_tlv_ioctl = 0; int ccid_esc_command = 0; PCSC_TLV_STRUCTURE *pcsc_tlv; #if defined(VERIFY_PIN) | defined(MODIFY_PIN) int offset; #endif #ifdef VERIFY_PIN PIN_VERIFY_STRUCTURE *pin_verify; #endif #ifdef MODIFY_PIN PIN_MODIFY_STRUCTURE *pin_modify; #endif int PIN_min_size = 4; int PIN_max_size = 8; UINT32 ActiveProtocol; /* table for bEntryValidationCondition * 0x01: Max size reached * 0x02: Validation key pressed * 0x04: Timeout occured */ int bEntryValidationCondition = 7; /* does the reader support PIN verification? */ length = sizeof bRecvBuffer; rv = SmartCardReader->SCardControl(SmartCardReader, CM_IOCTL_GET_FEATURE_REQUEST, NULL, 0, bRecvBuffer, &length); PCSC_ERROR_EXIT(rv, L"SCardControl") Print(L" TLV (%ld): ", length); for (i=0; i<length; i++) Print(L"%02X ", bRecvBuffer[i]); Print(L"\n"); PCSC_ERROR_CONT(rv, L"SCardControl(CM_IOCTL_GET_FEATURE_REQUEST)") if (length % sizeof(PCSC_TLV_STRUCTURE)) { Print(L"Inconsistent result! Bad TLV values!\n"); goto end; } /* get the number of elements instead of the complete size */ length /= sizeof(PCSC_TLV_STRUCTURE); pcsc_tlv = (PCSC_TLV_STRUCTURE *)bRecvBuffer; for (i = 0; i < length; i++) { switch (pcsc_tlv[i].tag) { case FEATURE_VERIFY_PIN_DIRECT: Print(L"Reader supports FEATURE_VERIFY_PIN_DIRECT\n"); verify_ioctl = ntohl(pcsc_tlv[i].value); break; case FEATURE_MODIFY_PIN_DIRECT: Print(L"Reader supports FEATURE_MODIFY_PIN_DIRECT\n"); modify_ioctl = ntohl(pcsc_tlv[i].value); break; case FEATURE_IFD_PIN_PROPERTIES: Print(L"Reader supports FEATURE_IFD_PIN_PROPERTIES\n"); pin_properties_ioctl = ntohl(pcsc_tlv[i].value); break; case FEATURE_MCT_READER_DIRECT: Print(L"Reader supports FEATURE_MCT_READER_DIRECT\n"); mct_readerdirect_ioctl = ntohl(pcsc_tlv[i].value); break; case FEATURE_GET_TLV_PROPERTIES: Print(L"Reader supports FEATURE_GET_TLV_PROPERTIES\n"); properties_in_tlv_ioctl = ntohl(pcsc_tlv[i].value); break; case FEATURE_CCID_ESC_COMMAND: Print(L"Reader supports FEATURE_CCID_ESC_COMMAND\n"); ccid_esc_command = ntohl(pcsc_tlv[i].value); break; default: Print(L"Can't parse tag", pcsc_tlv[i].tag); } } Print(L"\n"); if (properties_in_tlv_ioctl) { int value; int ret; length = sizeof bRecvBuffer; rv = SmartCardReader->SCardControl(SmartCardReader, properties_in_tlv_ioctl, NULL, 0, bRecvBuffer, &length); PCSC_ERROR_CONT(rv, L"SCardControl(GET_TLV_PROPERTIES)") Print(L"GET_TLV_PROPERTIES (%ld): ", length); for (i=0; i<length; i++) Print(L"%02X ", bRecvBuffer[i]); Print(L"\n"); Print(L"\nDisplay all the properties:\n"); parse_properties(bRecvBuffer, length); Print(L"\nFind a specific property:\n"); ret = PCSCv2Part10_find_TLV_property_by_tag_from_buffer(bRecvBuffer, length, PCSCv2_PART10_PROPERTY_wIdVendor, &value); if (ret) Print(L" wIdVendor: %d\n", ret); else Print(L" wIdVendor: %04X\n", value); ret = PCSCv2Part10_find_TLV_property_by_tag_from_protocol(SmartCardReader, PCSCv2_PART10_PROPERTY_wIdProduct, &value); if (ret) Print(L" wIdProduct %d\n", ret); else Print(L" wIdProduct: %04X\n", value); ret = PCSCv2Part10_find_TLV_property_by_tag_from_protocol(SmartCardReader, PCSCv2_PART10_PROPERTY_bMinPINSize, &value); if (0 == ret) { PIN_min_size = value; Print(L" PIN min size defined %d\n", PIN_min_size); } ret = PCSCv2Part10_find_TLV_property_by_tag_from_protocol(SmartCardReader, PCSCv2_PART10_PROPERTY_bMaxPINSize, &value); if (0 == ret) { PIN_max_size = value; Print(L" PIN max size defined %d\n", PIN_max_size); } ret = PCSCv2Part10_find_TLV_property_by_tag_from_protocol(SmartCardReader, PCSCv2_PART10_PROPERTY_bEntryValidationCondition, &value); if (0 == ret) { bEntryValidationCondition = value; Print(L" Entry Validation Condition defined %d\n", bEntryValidationCondition); } Print(L"\n"); } if (mct_readerdirect_ioctl) { unsigned char secoder_info[] = { 0x20, 0x70, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 }; length = sizeof bRecvBuffer; rv = SmartCardReader->SCardControl(SmartCardReader, mct_readerdirect_ioctl, secoder_info, sizeof(secoder_info), bRecvBuffer, &length); PCSC_ERROR_CONT(rv, L"SCardControl(MCT_READER_DIRECT)") Print(L"MCT_READER_DIRECT (%ld): ", length); for (i=0; i<length; i++) Print(L"%02X ", bRecvBuffer[i]); Print(L"\n"); } if (pin_properties_ioctl) { PIN_PROPERTIES_STRUCTURE *pin_properties; length = sizeof bRecvBuffer; rv = SmartCardReader->SCardControl(SmartCardReader, pin_properties_ioctl, NULL, 0, bRecvBuffer, &length); PCSC_ERROR_CONT(rv, L"SCardControl(pin_properties_ioctl)") Print(L"PIN PROPERTIES (%ld): ", length); for (i=0; i<length; i++) Print(L"%02X ", bRecvBuffer[i]); Print(L"\n"); pin_properties = (PIN_PROPERTIES_STRUCTURE *)bRecvBuffer; Print(L" wLcdLayout %04X\n", pin_properties -> wLcdLayout); Print(L" bEntryValidationCondition %d\n", pin_properties -> bEntryValidationCondition); Print(L" bTimeOut2 %d\n", pin_properties -> bTimeOut2); Print(L"\n"); } if (0 == verify_ioctl) { Print(L"Reader does not support PIN verification\n"); goto end; } /* SCardConnect */ rv = SmartCardReader->SCardConnect(SmartCardReader, SCARD_AM_CARD, SCARD_CA_COLDRESET, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &ActiveProtocol); PCSC_ERROR_EXIT(rv, L"SCardConnect") /* APDU select applet */ Print(L"Select applet: "); send_length = 11; memcpy(bSendBuffer, "\x00\xA4\x04\x00\x06\xA0\x00\x00\x00\x18\xFF", send_length); for (i=0; i<send_length; i++) Print(L" %02X", bSendBuffer[i]); Print(L"\n"); length = sizeof(bRecvBuffer); rv = SmartCardReader->SCardTransmit(SmartCardReader, bSendBuffer, send_length, bRecvBuffer, &length); Print(L" card response:"); for (i=0; i<length; i++) Print(L" %02X", bRecvBuffer[i]); Print(L"\n"); PCSC_ERROR_EXIT(rv, L"SCardTransmit") if ((bRecvBuffer[0] != 0x90) || (bRecvBuffer[1] != 0x00)) { Print(L"Error: test applet not found!\n"); goto end; } #ifdef VERIFY_PIN /* verify PIN */ Print(L" Secure verify PIN\n"); pin_verify = (PIN_VERIFY_STRUCTURE *)bSendBuffer; /* PC/SC v2.02.05 Part 10 PIN verification data structure */ pin_verify -> bTimerOut = 0x00; pin_verify -> bTimerOut2 = 0x00; pin_verify -> bmFormatString = 0x82; pin_verify -> bmPINBlockString = 0x04; pin_verify -> bmPINLengthFormat = 0x00; pin_verify -> wPINMaxExtraDigit = (PIN_min_size << 8) + PIN_max_size; pin_verify -> bEntryValidationCondition = bEntryValidationCondition; pin_verify -> bNumberMessage = 0x01; pin_verify -> wLangId = 0x0904; pin_verify -> bMsgIndex = 0x00; pin_verify -> bTeoPrologue[0] = 0x00; pin_verify -> bTeoPrologue[1] = 0x00; pin_verify -> bTeoPrologue[2] = 0x00; /* pin_verify -> ulDataLength = 0x00; we don't know the size yet */ /* APDU: 00 20 00 00 08 30 30 30 30 00 00 00 00 */ offset = 0; pin_verify -> abData[offset++] = 0x00; /* CLA */ pin_verify -> abData[offset++] = 0x20; /* INS: VERIFY */ pin_verify -> abData[offset++] = 0x00; /* P1 */ pin_verify -> abData[offset++] = 0x00; /* P2 */ pin_verify -> abData[offset++] = 0x08; /* Lc: 8 data bytes */ pin_verify -> abData[offset++] = 0x30; /* '0' */ pin_verify -> abData[offset++] = 0x30; /* '0' */ pin_verify -> abData[offset++] = 0x30; /* '0' */ pin_verify -> abData[offset++] = 0x30; /* '0' */ pin_verify -> abData[offset++] = 0x00; /* '\0' */ pin_verify -> abData[offset++] = 0x00; /* '\0' */ pin_verify -> abData[offset++] = 0x00; /* '\0' */ pin_verify -> abData[offset++] = 0x00; /* '\0' */ pin_verify -> ulDataLength = offset; /* APDU size */ send_length = sizeof(PIN_VERIFY_STRUCTURE) + offset; Print(L" command:"); for (i=0; i<length; i++) Print(L" %02X", bSendBuffer[i]); Print(L"\n"); Print(L"Enter your PIN: \n"); length = sizeof bRecvBuffer; rv = SmartCardReader->SCardControl(SmartCardReader, verify_ioctl, bSendBuffer, send_length, bRecvBuffer, &length); Print(L" card response:"); for (i=0; i<length; i++) Print(L" %02X", bRecvBuffer[i]); Print(L": %s\n", pinpad_return_codes(bRecvBuffer)); PCSC_ERROR_CONT(rv, L"SCardControl") /* verify PIN dump */ Print(L"\nverify PIN dump: "); send_length = 5; memcpy(bSendBuffer, "\x00\x40\x00\x00\xFF", send_length); for (i=0; i<send_length; i++) Print(L" %02X", bSendBuffer[i]); Print(L"\n"); length = sizeof(bRecvBuffer); rv = SmartCardReader->SCardTransmit(SmartCardReader, bSendBuffer, send_length, bRecvBuffer, &length); Print(L" card response:"); for (i=0; i<length; i++) Print(L" %02X", bRecvBuffer[i]); Print(L"\n"); PCSC_ERROR_EXIT(rv, L"SCardTransmit") if ((2 == length) && (0x6C == bRecvBuffer[0])) { Print(L"\nverify PIN dump: "); send_length = 5; memcpy(bSendBuffer, "\x00\x40\x00\x00\xFF", send_length); bSendBuffer[4] = bRecvBuffer[1]; for (i=0; i<send_length; i++) Print(L" %02X", bSendBuffer[i]); Print(L"\n"); length = sizeof(bRecvBuffer); rv = SmartCardReader->SCardTransmit(SmartCardReader, bSendBuffer, send_length, bRecvBuffer, &length); Print(L" card response:"); for (i=0; i<length; i++) Print(L" %02X", bRecvBuffer[i]); Print(L"\n"); PCSC_ERROR_EXIT(rv, L"SCardTransmit") }