#include "../globals.h" #ifdef CARDREADER_PCSC #include "atr.h" #include "../oscam-string.h" #if defined(__CYGWIN__) #define __reserved #define __nullnullterminated #include #include #endif #if !defined(__CYGWIN__) && !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) #include #include #include #include #endif #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) #include "pcsclite.h" #include "winscard.h" #include "wintypes.h" #include "reader.h" #endif #ifndef ERR_INVALID #define ERR_INVALID -1 #endif #if defined(__CYGWIN__) #undef OK #undef ERROR #undef LOBYTE #undef HIBYTE #endif #define OK 0 #define ERROR 1 struct pcsc_data { bool pcsc_has_card; char pcsc_name[128]; SCARDCONTEXT hContext; SCARDHANDLE hCard; DWORD dwActiveProtocol; }; static int32_t pcsc_init(struct s_reader *pcsc_reader) { ULONG rv; DWORD dwReaders = 0; LPSTR mszReaders = NULL; char *ptr, **readers = NULL; char *device = pcsc_reader->device; int32_t nbReaders; int32_t reader_nb; rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC establish context for PCSC pcsc_reader %s", device); SCARDCONTEXT hContext; memset(&hContext, 0, sizeof(hContext)); rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); if(rv == SCARD_S_SUCCESS) { if(!cs_malloc(&pcsc_reader->crdr_data, sizeof(struct pcsc_data))) { return ERROR; } struct pcsc_data *crdr_data = pcsc_reader->crdr_data; crdr_data->hContext = hContext; // here we need to list the pcsc readers and get the name from there, // the pcsc_reader->device should contain the pcsc_reader number // and after the actual device name is copied in crdr_data->pcsc_name . rv = SCardListReaders(crdr_data->hContext, NULL, NULL, &dwReaders); if(rv != SCARD_S_SUCCESS) { rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC failed listing readers [1] : (%lx)", (unsigned long)rv); return ERROR; } if(!cs_malloc(&mszReaders, dwReaders)) { return ERROR; } rv = SCardListReaders(crdr_data->hContext, NULL, mszReaders, &dwReaders); if(rv != SCARD_S_SUCCESS) { rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC failed listing readers [2]: (%lx)", (unsigned long)rv); NULLFREE(mszReaders); return ERROR; } /* Extract readers from the null separated string and get the total * number of readers */ nbReaders = 0; ptr = mszReaders; while(*ptr != '\0') { ptr += cs_strlen(ptr) + 1; nbReaders++; } if(nbReaders == 0) { rdr_log(pcsc_reader, "PCSC : no pcsc_reader found"); NULLFREE(mszReaders); return ERROR; } if(!cs_malloc(&readers, nbReaders * sizeof(char *))) { NULLFREE(mszReaders); return ERROR; } char* device_line; char* device_first; char* device_second; device_line = strdup((const char *)&pcsc_reader->device); device_first = strsep(&device_line, ":"); device_second = strsep(&device_line, ":"); reader_nb = atoi(device_first); /* fill the readers table */ nbReaders = 0; ptr = mszReaders; while(*ptr != '\0') { rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC pcsc_reader %d: %s", nbReaders, ptr); readers[nbReaders] = ptr; if ((reader_nb == -1) && (device_second != NULL) && strstr(ptr,device_second)){ reader_nb = nbReaders; } ptr += cs_strlen(ptr) + 1; nbReaders++; } if(reader_nb < 0 || reader_nb >= nbReaders) { rdr_log(pcsc_reader, "Wrong pcsc_reader index: %d", reader_nb); NULLFREE(mszReaders); NULLFREE(readers); NULLFREE(device_line); return ERROR; } if (readers) { snprintf(crdr_data->pcsc_name, sizeof(crdr_data->pcsc_name), "%s", readers[reader_nb]); NULLFREE(readers); } NULLFREE(mszReaders); NULLFREE(device_line); } else { rdr_log(pcsc_reader, "PCSC failed establish context (%lx)", (unsigned long)rv); return ERROR; } return OK; } static int32_t pcsc_do_api(struct s_reader *pcsc_reader, const uint8_t *buf, uint8_t *cta_res, uint16_t *cta_lr, int32_t l) { LONG rv; DWORD dwSendLength, dwRecvLength; *cta_lr = 0; if(!l) { rdr_log(pcsc_reader, "ERROR: Data length to be send to the pcsc_reader is %d", l); return ERROR; } char tmp[l * 3]; dwRecvLength = CTA_RES_LEN; struct pcsc_data *crdr_data = pcsc_reader->crdr_data; if(pcsc_reader->resetalways) { SCardReconnect(crdr_data->hCard, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_RESET_CARD, &crdr_data->dwActiveProtocol); } if(crdr_data->dwActiveProtocol == SCARD_PROTOCOL_T0) { // explanantion as to why we do the test on buf[4] : // Issuing a command without exchanging data : //To issue a command to the card that does not involve the exchange of data (either sent or received), the send and receive buffers must be formatted as follows. //The pbSendBuffer buffer must contain the CLA, INS, P1, and P2 values for the T=0 operation. The P3 value is not sent. (This is to differentiate the header from the case where 256 bytes are expected to be returned.) //The cbSendLength parameter must be set to four, the size of the T=0 header information (CLA, INS, P1, and P2). //The pbRecvBuffer will receive the SW1 and SW2 status codes from the operation. //The pcbRecvLength should be at least two and will be set to two upon return. if(buf[4]) { dwSendLength = l; } else { dwSendLength = l - 1; } rdr_log_dbg(pcsc_reader, D_DEVICE, "sending %lu bytes to PCSC : %s", (unsigned long)dwSendLength, cs_hexdump(1, buf, l, tmp, sizeof(tmp))); rv = SCardTransmit(crdr_data->hCard, SCARD_PCI_T0, (LPCBYTE) buf, dwSendLength, NULL, (LPBYTE) cta_res, (LPDWORD) &dwRecvLength); *cta_lr = dwRecvLength; } else if(crdr_data->dwActiveProtocol == SCARD_PROTOCOL_T1) { dwSendLength = l; rdr_log_dbg(pcsc_reader, D_DEVICE, "sending %lu bytes to PCSC : %s", (unsigned long)dwSendLength, cs_hexdump(1, buf, l, tmp, sizeof(tmp))); rv = SCardTransmit(crdr_data->hCard, SCARD_PCI_T1, (LPCBYTE) buf, dwSendLength, NULL, (LPBYTE) cta_res, (LPDWORD) &dwRecvLength); *cta_lr = dwRecvLength; } else { rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC invalid protocol (T=%lu)", (unsigned long)crdr_data->dwActiveProtocol); return ERROR; } rdr_log_dbg(pcsc_reader, D_DEVICE, "received %d bytes from PCSC with rv=%lx : %s", *cta_lr, (unsigned long)rv, cs_hexdump(1, cta_res, *cta_lr, tmp, sizeof(tmp))); rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC doapi (%lx ) (T=%d), %d", (unsigned long)rv, (crdr_data->dwActiveProtocol == SCARD_PROTOCOL_T0 ? 0 : 1), *cta_lr); if(rv == SCARD_S_SUCCESS) { return OK; } else { return ERROR; } } static int32_t pcsc_activate_card(struct s_reader *pcsc_reader, uint8_t *atr, uint16_t *atr_size) { struct pcsc_data *crdr_data = pcsc_reader->crdr_data; LONG rv; DWORD dwState, dwAtrLen, dwReaderLen; unsigned char pbAtr[ATR_MAX_SIZE]; char tmp[sizeof(pbAtr) * 3 + 1]; rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC initializing card in (%s)", crdr_data->pcsc_name); dwAtrLen = sizeof(pbAtr); dwReaderLen = 0; rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC resetting card in (%s) with handle %" PRIuPTR, crdr_data->pcsc_name, (uintptr_t)crdr_data->hCard); rv = SCardReconnect(crdr_data->hCard, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_RESET_CARD, &crdr_data->dwActiveProtocol); if(rv != SCARD_S_SUCCESS) { rdr_log_dbg(pcsc_reader, D_DEVICE, "ERROR: PCSC failed to reset card (%lx)", (unsigned long)rv); return ERROR; } rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC resetting done on card in (%s)", crdr_data->pcsc_name); rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC Protocol (T=%d)", (crdr_data->dwActiveProtocol == SCARD_PROTOCOL_T0 ? 0 : 1)); rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC getting ATR for card in (%s)", crdr_data->pcsc_name); rv = SCardStatus(crdr_data->hCard, NULL, &dwReaderLen, &dwState, &crdr_data->dwActiveProtocol, pbAtr, &dwAtrLen); if(rv == SCARD_S_SUCCESS) { rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC Protocol (T=%d)", (crdr_data->dwActiveProtocol == SCARD_PROTOCOL_T0 ? 0 : 1)); memcpy(atr, pbAtr, dwAtrLen); *atr_size = dwAtrLen; rdr_log(pcsc_reader, "ATR: %s", cs_hexdump(1, (uint8_t *)pbAtr, dwAtrLen, tmp, sizeof(tmp))); memcpy(pcsc_reader->card_atr, pbAtr, dwAtrLen); pcsc_reader->card_atr_length = dwAtrLen; return OK; } else { rdr_log_dbg(pcsc_reader, D_DEVICE, "ERROR: PCSC failed to get ATR for card (%lx)", (unsigned long)rv); } return ERROR; } static int32_t pcsc_activate(struct s_reader *reader, struct s_ATR *atr) { unsigned char atrarr[ATR_MAX_SIZE]; uint16_t atr_size = 0; if(pcsc_activate_card(reader, atrarr, &atr_size) == OK) { if(ATR_InitFromArray(atr, atrarr, atr_size) != ERROR) // ATR is OK or softfail malformed { return OK; } else { return ERROR; } } else { return ERROR; } } static int32_t pcsc_check_card_inserted(struct s_reader *pcsc_reader) { struct pcsc_data *crdr_data = pcsc_reader->crdr_data; DWORD dwState, dwAtrLen, dwReaderLen; unsigned char pbAtr[64]; SCARDHANDLE rv; dwAtrLen = sizeof(pbAtr); rv = 0; dwState = 0; dwReaderLen = 0; // Do we have a card ? if(!crdr_data->pcsc_has_card && !crdr_data->hCard) { // try connecting to the card rv = SCardConnect(crdr_data->hContext, crdr_data->pcsc_name, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &crdr_data->hCard, &crdr_data->dwActiveProtocol); if(rv == (SCARDHANDLE)SCARD_E_NO_SMARTCARD) { // no card in pcsc_reader crdr_data->pcsc_has_card = 0; if(crdr_data->hCard) { SCardDisconnect(crdr_data->hCard, SCARD_RESET_CARD); crdr_data->hCard = 0; } // rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC card in %s removed / absent [dwstate=%lx rv=(%lx)]", crdr_data->pcsc_name, dwState, (unsigned long)rv ); return OK; } else if(rv == (SCARDHANDLE)SCARD_W_UNRESPONSIVE_CARD) { // there is a problem with the card in the pcsc_reader crdr_data->pcsc_has_card = 0; crdr_data->hCard = 0; rdr_log(pcsc_reader, "PCSC card in %s is unresponsive. Eject and re-insert please.", crdr_data->pcsc_name); return ERROR; } else if(rv == SCARD_S_SUCCESS) { // we have a card crdr_data->pcsc_has_card = 1; rdr_log(pcsc_reader, "PCSC was opened with handle: %" PRIuPTR, (uintptr_t)crdr_data->hCard); } else { // if we get here we have a bigger problem -> display status and debug // rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC pcsc_reader %s status [dwstate=%lx rv=(%lx)]", crdr_data->pcsc_name, dwState, (unsigned long)rv ); return ERROR; } } // if we get there the card is ready, check its status rv = SCardStatus(crdr_data->hCard, NULL, &dwReaderLen, &dwState, &crdr_data->dwActiveProtocol, pbAtr, &dwAtrLen); if(rv == SCARD_S_SUCCESS && (dwState & (SCARD_PRESENT | SCARD_NEGOTIABLE | SCARD_POWERED))) { return OK; } else { SCardDisconnect(crdr_data->hCard, SCARD_RESET_CARD); crdr_data->hCard = 0; crdr_data->pcsc_has_card = 0; } return ERROR; } static int32_t pcsc_get_status(struct s_reader *reader, int32_t *in) { struct pcsc_data *crdr_data = reader->crdr_data; int32_t ret = pcsc_check_card_inserted(reader); *in = crdr_data->pcsc_has_card; return ret; } static int32_t pcsc_close(struct s_reader *pcsc_reader) { struct pcsc_data *crdr_data = pcsc_reader->crdr_data; rdr_log_dbg(pcsc_reader, D_IFD, "PCSC : Closing device %s", pcsc_reader->device); SCardDisconnect(crdr_data->hCard, SCARD_LEAVE_CARD); SCardReleaseContext(crdr_data->hContext); return OK; } const struct s_cardreader cardreader_pcsc = { .desc = "pcsc", .typ = R_PCSC, .skip_extra_atr_parsing = 1, .skip_t1_command_retries = 1, .skip_setting_ifsc = 1, .reader_init = pcsc_init, .get_status = pcsc_get_status, .activate = pcsc_activate, .card_write = pcsc_do_api, .close = pcsc_close, }; #endif