/* scardcontrol.c: sample code to use/test SCardControl() API Copyright (C) 2004-2011 Ludovic Rousseau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #ifdef __APPLE__ #include #include #else #include #endif #include #include "PCSCv2part10.h" #define VERIFY_PIN #undef MODIFY_PIN #undef GET_GEMPC_FIRMWARE #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #define IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE SCARD_CTL_CODE(1) #define BLUE "\33[34m" #define RED "\33[31m" #define BRIGHT_RED "\33[01;31m" #define GREEN "\33[32m" #define NORMAL "\33[0m" #define MAGENTA "\33[35m" /* DWORD printf(3) format */ #ifdef __APPLE__ /* Apple defines DWORD as uint32_t so %d is correct */ #define LF #else /* pcsc-lite defines DWORD as unsigned long so %ld is correct */ #define LF "l" #endif /* PCSC error message pretty print */ #define PCSC_ERROR_EXIT(rv, text) \ if (rv != SCARD_S_SUCCESS) \ { \ printf(text ": " RED "%s (0x%"LF"X)\n" NORMAL, pcsc_stringify_error(rv), rv); \ goto end; \ } \ else \ printf(text ": " BLUE "OK\n\n" NORMAL); #define PCSC_ERROR_CONT(rv, text) \ if (rv != SCARD_S_SUCCESS) \ printf(text ": " BLUE "%s (0x%"LF"X)\n" NORMAL, pcsc_stringify_error(rv), rv); \ else \ printf(text ": " BLUE "OK\n\n" NORMAL); #define PRINT_GREEN(text, value) \ printf("%s: " GREEN "%s\n" NORMAL, text, value) #define PRINT_GREEN_DEC(text, value) \ printf("%s: " GREEN "%d\n" NORMAL, text, value) #define PRINT_RED_DEC(text, value) \ printf("%s: " RED "%d\n" NORMAL, text, value) #define PRINT_GREEN_HEX2(text, value) \ printf("%s: " GREEN "0x%02X\n" NORMAL, text, value) #define PRINT_GREEN_HEX4(text, value) \ printf("%s: " GREEN "0x%04X\n" NORMAL, text, value) static void parse_properties(unsigned char *bRecvBuffer, int length) { unsigned char *p; int i; p = bRecvBuffer; while (p-bRecvBuffer < length) { int tag, len, value; tag = *p++; len = *p++; switch(len) { case 1: value = *p; break; case 2: value = *p + (*(p+1)<<8); break; case 4: value = *p + (*(p+1)<<8) + (*(p+2)<<16) + (*(p+3)<<24); break; default: value = -1; } switch(tag) { case PCSCv2_PART10_PROPERTY_wLcdLayout: PRINT_GREEN_HEX4(" wLcdLayout", value); break; case PCSCv2_PART10_PROPERTY_bEntryValidationCondition: PRINT_GREEN_HEX2(" bEntryValidationCondition", value); break; case PCSCv2_PART10_PROPERTY_bTimeOut2: PRINT_GREEN_HEX2(" bTimeOut2", value); break; case PCSCv2_PART10_PROPERTY_wLcdMaxCharacters: PRINT_GREEN_HEX4(" wLcdMaxCharacters", value); break; case PCSCv2_PART10_PROPERTY_wLcdMaxLines: PRINT_GREEN_HEX4(" wLcdMaxLines", value); break; case PCSCv2_PART10_PROPERTY_bMinPINSize: PRINT_GREEN_HEX2(" bMinPINSize", value); break; case PCSCv2_PART10_PROPERTY_bMaxPINSize: PRINT_GREEN_HEX2(" bMaxPINSize", value); break; case PCSCv2_PART10_PROPERTY_sFirmwareID: printf(" sFirmwareID: " GREEN); for (i=0; i\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 %"LF"X\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: %"LF"X\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 "%"LF"d\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 bEntryValidationCondition; PRINT_GREEN_HEX4(" wLcdLayout", pin_properties -> wLcdLayout); PRINT_GREEN_DEC(" bEntryValidationCondition", 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 bTimerOut = 0x00; pin_verify -> bTimerOut2 = 0x00; pin_verify -> bmFormatString = 0x82; pin_verify -> bmPINBlockString = 0x08; 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 */ length = sizeof(PIN_VERIFY_STRUCTURE) + offset; printf(" command:"); for (i=0; i 0) { /* read the fake digits */ char in[40]; /* 4 digits + \n + \0 */ char *s = fgets(in, sizeof(in), stdin); if (s) printf("keyboard sent: %s", in); } else /* if it is not a keyboard */ printf("\n"); } printf(" card response:"); for (i=0; i bTimerOut = 0x00; pin_modify -> bTimerOut2 = 0x00; pin_modify -> bmFormatString = 0x82; pin_modify -> bmPINBlockString = 0x04; pin_modify -> bmPINLengthFormat = 0x00; pin_modify -> bInsertionOffsetOld = 0x00; /* offset from APDU start */ pin_modify -> bInsertionOffsetNew = 0x04; /* offset from APDU start */ pin_modify -> wPINMaxExtraDigit = (PIN_min_size << 8) + PIN_max_size; pin_modify -> bConfirmPIN = 0x03; /* b0 set = confirmation requested */ /* b1 set = current PIN entry requested */ pin_modify -> bEntryValidationCondition = bEntryValidationCondition; pin_modify -> bNumberMessage = 0x03; /* see table above */ pin_modify -> wLangId = 0x0904; pin_modify -> bMsgIndex1 = 0x00; pin_modify -> bMsgIndex2 = 0x01; pin_modify -> bMsgIndex3 = 0x02; pin_modify -> bTeoPrologue[0] = 0x00; pin_modify -> bTeoPrologue[1] = 0x00; pin_modify -> bTeoPrologue[2] = 0x00; /* pin_modify -> 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_modify -> abData[offset++] = 0x00; /* CLA */ pin_modify -> abData[offset++] = 0x24; /* INS: CHANGE/UNBLOCK */ pin_modify -> abData[offset++] = 0x00; /* P1 */ pin_modify -> abData[offset++] = 0x00; /* P2 */ pin_modify -> abData[offset++] = 0x08; /* Lc: 2x8 data bytes */ pin_modify -> abData[offset++] = 0x30; /* '0' old PIN */ pin_modify -> abData[offset++] = 0x30; /* '0' */ pin_modify -> abData[offset++] = 0x30; /* '0' */ pin_modify -> abData[offset++] = 0x30; /* '0' */ pin_modify -> abData[offset++] = 0x30; /* '0' new PIN */ pin_modify -> abData[offset++] = 0x30; /* '0' */ pin_modify -> abData[offset++] = 0x30; /* '0' */ pin_modify -> abData[offset++] = 0x30; /* '0' */ pin_modify -> ulDataLength = offset; /* APDU size */ length = sizeof(PIN_MODIFY_STRUCTURE) + offset; printf(" command:"); for (i=0; i 0) { /* read the fake digits */ char in[40]; /* 4 digits + \n + \0 */ char *ret; ret = fgets(in, sizeof(in), stdin); if (ret) printf("keyboard sent: %s", in); } else { /* if it is not a keyboard */ printf("\n"); /* exit the for() loop */ break; } } } printf(" card response:"); for (i=0; i