static uint32 handle_State(IRP* irp) { LONG rv; SCARDHANDLE hCard; DWORD state = 0, protocol = 0; DWORD readerLen; DWORD atrLen = MAX_ATR_SIZE; char * readerName; BYTE pbAtr[MAX_ATR_SIZE]; #ifdef WITH_DEBUG_SCARD int i; #endif stream_seek(irp->input, 0x24); stream_seek_uint32(irp->input); /* atrLen */ stream_seek(irp->input, 0x0c); stream_read_uint32(irp->input, hCard); stream_seek(irp->input, 0x04); #ifdef SCARD_AUTOALLOCATE readerLen = SCARD_AUTOALLOCATE; rv = SCardStatus(hCard, (LPSTR) &readerName, &readerLen, &state, &protocol, pbAtr, &atrLen); #else readerLen = 256; readerName = xmalloc(readerLen); rv = SCardStatus(hCard, (LPSTR) readerName, &readerLen, &state, &protocol, pbAtr, &atrLen); #endif if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv); return sc_output_return(irp, rv); } DEBUG_SCARD("Success (hcard: 0x%08x len: %d state: 0x%08x, proto: 0x%08x)", (unsigned) hCard, (int) atrLen, (unsigned) state, (unsigned) protocol); #ifdef WITH_DEBUG_SCARD printf(" ATR: "); for (i = 0; i < atrLen; i++) printf("%02x%c", pbAtr[i], (i == atrLen - 1) ? ' ' : ':'); printf("\n"); #endif state = sc_map_state(state); stream_write_uint32(irp->output, state); stream_write_uint32(irp->output, protocol); stream_write_uint32(irp->output, atrLen); stream_write_uint32(irp->output, 0x00000001); stream_write_uint32(irp->output, atrLen); stream_write(irp->output, pbAtr, atrLen); sc_output_repos(irp, atrLen); sc_output_alignment(irp, 8); #ifdef SCARD_AUTOALLOCATE xfree(readerName); #else xfree(readerName); #endif return rv; }
static DWORD handle_Status(IRP *irp, boolean wide) { LONG rv; SCARDHANDLE hCard; DWORD state, protocol; DWORD readerLen = 0; DWORD atrLen = 0; char * readerName; BYTE pbAtr[MAX_ATR_SIZE]; uint32 dataLength; int pos, poslen1, poslen2; #ifdef WITH_DEBUG_SCARD int i; #endif stream_seek(irp->input, 0x24); stream_read_uint32(irp->input, readerLen); stream_read_uint32(irp->input, atrLen); stream_seek(irp->input, 0x0c); stream_read_uint32(irp->input, hCard); stream_seek(irp->input, 0x4); atrLen = MAX_ATR_SIZE; #ifdef SCARD_AUTOALLOCATE readerLen = SCARD_AUTOALLOCATE; rv = SCardStatus(hCard, (LPSTR) &readerName, &readerLen, &state, &protocol, pbAtr, &atrLen); #else readerLen = 256; readerName = xmalloc(readerLen); rv = SCardStatus(hCard, (LPSTR) readerName, &readerLen, &state, &protocol, pbAtr, &atrLen); #endif if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv); return sc_output_return(irp, rv); } DEBUG_SCARD("Success (state: 0x%08x, proto: 0x%08x)", (unsigned) state, (unsigned) protocol); DEBUG_SCARD(" Reader: \"%s\"", readerName ? readerName : "NULL"); #ifdef WITH_DEBUG_SCARD printf(" ATR: "); for (i = 0; i < atrLen; i++) printf("%02x%c", pbAtr[i], (i == atrLen - 1) ? ' ' : ':'); printf("\n"); #endif state = sc_map_state(state); poslen1 = stream_get_pos(irp->output); stream_write_uint32(irp->output, readerLen); stream_write_uint32(irp->output, 0x00020000); stream_write_uint32(irp->output, state); stream_write_uint32(irp->output, protocol); stream_write(irp->output, pbAtr, atrLen); if (atrLen < 32) stream_write_zero(irp->output, 32 - atrLen); stream_write_uint32(irp->output, atrLen); poslen2 = stream_get_pos(irp->output); stream_write_uint32(irp->output, readerLen); dataLength = sc_output_string(irp, readerName, wide); dataLength += sc_output_string(irp, "\0", wide); sc_output_repos(irp, dataLength); pos = stream_get_pos(irp->output); stream_set_pos(irp->output, poslen1); stream_write_uint32(irp->output,dataLength); stream_set_pos(irp->output, poslen2); stream_write_uint32(irp->output,dataLength); stream_set_pos(irp->output, pos); sc_output_alignment(irp, 8); #ifdef SCARD_AUTOALLOCATE /* SCardFreeMemory(NULL, readerName); */ free(readerName); #else xfree(readerName); #endif return rv; }
static uint32 handle_ListReaders(IRP* irp, boolean wide) { uint32 len, rv; SCARDCONTEXT hContext; DWORD dwReaders; char *readerList = NULL, *walker; int elemLength, dataLength; int pos, poslen1, poslen2; stream_seek(irp->input, 8); stream_read_uint32(irp->input, len); stream_seek(irp->input, 0x1c); stream_read_uint32(irp->input, len); if (len != 4) return SCARD_F_INTERNAL_ERROR; stream_read_uint32(irp->input, hContext); /* ignore rest of [MS-RDPESC] 2.2.2.4 ListReaders_Call */ rv = SCARD_S_SUCCESS; #ifdef SCARD_AUTOALLOCATE dwReaders = SCARD_AUTOALLOCATE; rv = SCardListReaders(hContext, NULL, (LPSTR) &readerList, &dwReaders); #else rv = SCardListReaders(hContext, NULL, NULL, &dwReaders); readerList = xmalloc(dwReaders); rv = SCardListReaders(hContext, NULL, readerList, &dwReaders); #endif if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv); return rv; } /* DEBUG_SCARD("Success 0x%08x %d %d", (unsigned) hContext, (unsigned) cchReaders, (int) strlen(readerList));*/ poslen1 = stream_get_pos(irp->output); stream_seek_uint32(irp->output); stream_write_uint32(irp->output, 0x01760650); poslen2 = stream_get_pos(irp->output); stream_seek_uint32(irp->output); walker = readerList; dataLength = 0; while (1) { elemLength = strlen(walker); if (elemLength == 0) break; dataLength += sc_output_string(irp, walker, wide); walker += elemLength + 1; elemLength = strlen(walker); } dataLength += sc_output_string(irp, "\0", wide); pos = stream_get_pos(irp->output); stream_set_pos(irp->output, poslen1); stream_write_uint32(irp->output, dataLength); stream_set_pos(irp->output, poslen2); stream_write_uint32(irp->output, dataLength); stream_set_pos(irp->output, pos); sc_output_repos(irp, dataLength); sc_output_alignment(irp, 8); #ifdef SCARD_AUTOALLOCATE SCardFreeMemory(hContext, readerList); #else xfree(readerList); #endif return rv; }
static uint32 handle_GetStatusChange(IRP* irp, boolean wide) { LONG rv; SCARDCONTEXT hContext; DWORD dwTimeout = 0; DWORD readerCount = 0; SCARD_READERSTATE *readerStates, *cur; int i; stream_seek(irp->input, 0x18); stream_read_uint32(irp->input, dwTimeout); stream_read_uint32(irp->input, readerCount); stream_seek(irp->input, 8); stream_read_uint32(irp->input, hContext); stream_seek(irp->input, 4); DEBUG_SCARD("context: 0x%08x, timeout: 0x%08x, count: %d", (unsigned) hContext, (unsigned) dwTimeout, (int) readerCount); if (readerCount > 0) { readerStates = xzalloc(readerCount * sizeof(SCARD_READERSTATE)); if (!readerStates) return sc_output_return(irp, SCARD_E_NO_MEMORY); for (i = 0; i < readerCount; i++) { cur = &readerStates[i]; stream_seek(irp->input, 4); /* * TODO: on-wire is little endian; need to either * convert to host endian or fix the headers to * request the order we want */ stream_read_uint32(irp->input, cur->dwCurrentState); stream_read_uint32(irp->input, cur->dwEventState); stream_read_uint32(irp->input, cur->cbAtr); stream_read(irp->input, cur->rgbAtr, 32); stream_seek(irp->input, 4); /* reset high bytes? */ cur->dwCurrentState &= 0x0000FFFF; cur->dwEventState &= 0x0000FFFF; cur->dwEventState = 0; } for (i = 0; i < readerCount; i++) { cur = &readerStates[i]; uint32 dataLength; stream_seek(irp->input, 8); stream_read_uint32(irp->input, dataLength); sc_input_repos(irp, sc_input_string(irp, (char **) &cur->szReader, dataLength, wide)); DEBUG_SCARD(" \"%s\"", cur->szReader ? cur->szReader : "NULL"); DEBUG_SCARD(" user: 0x%08x, state: 0x%08x, event: 0x%08x", (unsigned) cur->pvUserData, (unsigned) cur->dwCurrentState, (unsigned) cur->dwEventState); if (strcmp(cur->szReader, "\\\\?PnP?\\Notification") == 0) cur->dwCurrentState |= SCARD_STATE_IGNORE; } } else { readerStates = NULL; } rv = SCardGetStatusChange(hContext, (DWORD) dwTimeout, readerStates, (DWORD) readerCount); if (rv != SCARD_S_SUCCESS) DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv); else DEBUG_SCARD("Success"); stream_write_uint32(irp->output, readerCount); stream_write_uint32(irp->output, 0x00084dd8); stream_write_uint32(irp->output, readerCount); for (i = 0; i < readerCount; i++) { cur = &readerStates[i]; DEBUG_SCARD(" \"%s\"", cur->szReader ? cur->szReader : "NULL"); DEBUG_SCARD(" user: 0x%08x, state: 0x%08x, event: 0x%08x\n", (unsigned) cur->pvUserData, (unsigned) cur->dwCurrentState, (unsigned) cur->dwEventState); /* TODO: do byte conversions if necessary */ stream_write_uint32(irp->output, cur->dwCurrentState); stream_write_uint32(irp->output, cur->dwEventState); stream_write_uint32(irp->output, cur->cbAtr); stream_write(irp->output, cur->rgbAtr, 32); stream_write_zero(irp->output, 4); xfree((void *)cur->szReader); } sc_output_alignment(irp, 8); xfree(readerStates); return rv; }
static uint32 handle_GetAttrib(IRP* irp) { LONG rv; SCARDHANDLE hCard; DWORD dwAttrId = 0, dwAttrLen = 0; DWORD attrLen = 0; uint8* pbAttr = NULL; stream_seek(irp->input, 0x20); stream_read_uint32(irp->input, dwAttrId); stream_seek(irp->input, 0x4); stream_read_uint32(irp->input, dwAttrLen); stream_seek(irp->input, 0xC); stream_read_uint32(irp->input, hCard); DEBUG_SCARD("hcard: 0x%08x, attrib: 0x%08x (%d bytes)\n", (unsigned) hCard, (unsigned) dwAttrId, (int) dwAttrLen); #ifdef SCARD_AUTOALLOCATE if(dwAttrLen == 0) { attrLen = 0; } else { attrLen = SCARD_AUTOALLOCATE; } #endif rv = SCardGetAttrib(hCard, dwAttrId, attrLen == 0 ? NULL : (uint8*) &pbAttr, &attrLen); if(dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_A && rv == SCARD_E_UNSUPPORTED_FEATURE) { rv = SCardGetAttrib(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME_W, attrLen == 0 ? NULL : (uint8*) &pbAttr, &attrLen); } if(dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_W && rv == SCARD_E_UNSUPPORTED_FEATURE) { rv = SCardGetAttrib(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME_A, attrLen == 0 ? NULL : (uint8*) &pbAttr, &attrLen); } if(attrLen > dwAttrLen && pbAttr != NULL) { rv = SCARD_E_INSUFFICIENT_BUFFER; } dwAttrLen = attrLen; if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned int) rv); free(pbAttr); return sc_output_return(irp, rv); } else { DEBUG_SCARD("Success (%d bytes)", (int) dwAttrLen); stream_write_uint32(irp->output, dwAttrLen); stream_write_uint32(irp->output, 0x00000200); stream_write_uint32(irp->output, dwAttrLen); if (!pbAttr) { stream_write_zero(irp->output, dwAttrLen); } else { stream_write(irp->output, pbAttr, dwAttrLen); } sc_output_repos(irp, dwAttrLen); /* align to multiple of 4 */ stream_write_uint32(irp->output, 0); } sc_output_alignment(irp, 8); xfree(pbAttr); return rv; }
static uint32 handle_LocateCardsByATR(IRP* irp, boolean wide) { LONG rv; int i, j, k; SCARDCONTEXT hContext; uint32 atrMaskCount = 0; uint32 readerCount = 0; SCARD_READERSTATE* cur = NULL; SCARD_READERSTATE* rsCur = NULL; SCARD_READERSTATE* readerStates = NULL; SERVER_SCARD_ATRMASK* curAtr = NULL; SERVER_SCARD_ATRMASK* pAtrMasks = NULL; stream_seek(irp->input, 0x2C); stream_read_uint32(irp->input, hContext); stream_read_uint32(irp->input, atrMaskCount); pAtrMasks = xmalloc(atrMaskCount * sizeof(SERVER_SCARD_ATRMASK)); if (!pAtrMasks) return sc_output_return(irp, SCARD_E_NO_MEMORY); for (i = 0; i < atrMaskCount; i++) { stream_read_uint32(irp->input, pAtrMasks[i].cbAtr); stream_read(irp->input, pAtrMasks[i].rgbAtr, 36); stream_read(irp->input, pAtrMasks[i].rgbMask, 36); } stream_read_uint32(irp->input, readerCount); readerStates = xzalloc(readerCount * sizeof(SCARD_READERSTATE)); if (!readerStates) return sc_output_return(irp, SCARD_E_NO_MEMORY); for (i = 0; i < readerCount; i++) { cur = &readerStates[i]; stream_seek(irp->input, 4); /* * TODO: on-wire is little endian; need to either * convert to host endian or fix the headers to * request the order we want */ stream_read_uint32(irp->input, cur->dwCurrentState); stream_read_uint32(irp->input, cur->dwEventState); stream_read_uint32(irp->input, cur->cbAtr); stream_read(irp->input, cur->rgbAtr, 32); stream_seek(irp->input, 4); /* reset high bytes? */ cur->dwCurrentState &= 0x0000FFFF; cur->dwEventState &= 0x0000FFFF; cur->dwEventState = 0; } for (i = 0; i < readerCount; i++) { cur = &readerStates[i]; uint32 dataLength; stream_seek(irp->input, 8); stream_read_uint32(irp->input, dataLength); sc_input_repos(irp, sc_input_string(irp, (char **) &cur->szReader, dataLength, wide)); DEBUG_SCARD(" \"%s\"", cur->szReader ? cur->szReader : "NULL"); DEBUG_SCARD(" user: 0x%08x, state: 0x%08x, event: 0x%08x", (unsigned) cur->pvUserData, (unsigned) cur->dwCurrentState, (unsigned) cur->dwEventState); if (strcmp(cur->szReader, "\\\\?PnP?\\Notification") == 0) cur->dwCurrentState |= SCARD_STATE_IGNORE; } rv = SCardGetStatusChange(hContext, 0x00000001, readerStates, readerCount); if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv); return sc_output_return(irp, rv); } DEBUG_SCARD("Success"); for (i = 0, curAtr = pAtrMasks; i < atrMaskCount; i++, curAtr++) { for (j = 0, rsCur = readerStates; j < readerCount; j++, rsCur++) { boolean equal = 1; for (k = 0; k < cur->cbAtr; k++) { if ((curAtr->rgbAtr[k] & curAtr->rgbMask[k]) != (rsCur->rgbAtr[k] & curAtr->rgbMask[k])) { equal = 0; break; } } if (equal) { rsCur->dwEventState |= 0x00000040; /* SCARD_STATE_ATRMATCH 0x00000040 */ } } } stream_write_uint32(irp->output, readerCount); stream_write_uint32(irp->output, 0x00084dd8); stream_write_uint32(irp->output, readerCount); for (i = 0, rsCur = readerStates; i < readerCount; i++, rsCur++) { stream_write_uint32(irp->output, cur->dwCurrentState); stream_write_uint32(irp->output, cur->dwEventState); stream_write_uint32(irp->output, cur->cbAtr); stream_write(irp->output, cur->rgbAtr, 32); stream_write_zero(irp->output, 4); xfree((void*) cur->szReader); } sc_output_alignment(irp, 8); free(readerStates); return rv; }
void PCSCResourceManager::run() { SCARDCONTEXT context; LONG rv; while (true) { rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &context); if (rv == SCARD_S_SUCCESS) { DWORD readerNum = SCARD_AUTOALLOCATE; LPSTR readerNames = NULL; do { rv = SCardListReaders(context, NULL, (LPSTR) &readerNames, &readerNum); if (rv == SCARD_S_SUCCESS) { for (LPCSTR pch = readerNames; *pch != '\0'; pch += strlen(pch) + 1) { int i; for (i = 0; i < m_availabeReaders.size(); i++) if (0 == strcmp(m_availabeReaders[i]->name(), pch)) break; if (i == m_availabeReaders.size()) { SCardReader *reader = new SCardReader(pch); m_availabeReaders.append(reader); connect(reader, SIGNAL(unavailable(LPCSTR)), SLOT(clearUnavailabeReader(LPCSTR))); reader->start(); emit readerPluged(reader); } } (void) SCardFreeMemory(context, readerNames); } else std::cout << pcsc_stringify_error(rv) << std::endl; if (rv == SCARD_S_SUCCESS || rv == SCARD_E_NO_READERS_AVAILABLE) { SCARD_READERSTATE readerStates; readerStates.szReader = "\\\\?PnP?\\Notification"; readerStates.dwCurrentState = SCARD_STATE_UNAWARE; rv = SCardGetStatusChange(context, INFINITE, &readerStates, 1); if (rv != SCARD_E_TIMEOUT || rv != SCARD_S_SUCCESS) { (void) SCardReleaseContext(context); break; } } else { (void) SCardReleaseContext(context); break; } } while (true); } else { std::cout << pcsc_stringify_error(rv) << std::endl; QThread::sleep(PCSC_ERROR_BREAK_TIME); } } }
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 */
static unsigned short pcsc_transmit(cardreader_t* cr, const bytestring_t* command, bytestring_t* result) { pcsc_data_t* pcsc = cr->extra_data; BYTE REC_DAT[MAX_PCSC_READ_LENGTH]; DWORD REC_LEN=MAX_PCSC_READ_LENGTH; unsigned short SW; if (cr->protocol==SCARD_PROTOCOL_T0) { pcsc->status = SCardTransmit(pcsc->hcard,SCARD_PCI_T0, bytestring_get_data(command), bytestring_get_size(command), SCARD_PCI_NULL, REC_DAT,&REC_LEN); } else if (cr->protocol==SCARD_PROTOCOL_T1) { pcsc->status = SCardTransmit(pcsc->hcard,SCARD_PCI_T1, bytestring_get_data(command), bytestring_get_size(command), SCARD_PCI_NULL, REC_DAT,&REC_LEN); } else { log_printf(LOG_ERROR,"Unknown smartcard protocol: %i",cr->protocol); return CARDPEEK_ERROR_SW; } if (pcsc->status!=SCARD_S_SUCCESS) { log_printf(LOG_ERROR,"Failed to transmit command to card: %s (error 0x%08x).", pcsc_stringify_error(pcsc->status), pcsc->status ); return CARDPEEK_ERROR_SW; } if (REC_LEN>=2) { bytestring_assign_data(result,REC_LEN-2,REC_DAT); SW = (REC_DAT[REC_LEN-2]<<8)|REC_DAT[REC_LEN-1]; } else if (REC_LEN==1) { bytestring_clear(result); SW = REC_DAT[0]; } else { log_printf(LOG_ERROR,"Transmited %i bytes to the card (%s), but recieved a response of length %i, without any status word included.", bytestring_get_size(command), pcsc_stringify_protocol(cr->protocol), REC_LEN); return CARDPEEK_ERROR_SW; } return SW; }
static int pcsc_connect(cardreader_t *cr, unsigned prefered_protocol) { DWORD attr_maxinput = 0; DWORD attr_maxinput_len = sizeof(unsigned int); SCARD_READERSTATE reader_state; pcsc_data_t* pcsc = cr->extra_data; int counter = 0; void *progress; memset(&reader_state,0,sizeof(reader_state)); reader_state.szReader = cr->name+7; reader_state.dwCurrentState = SCARD_STATE_UNAWARE; pcsc->status = SCardGetStatusChange(pcsc->hcontext,INFINITE,&reader_state,1); if (pcsc->status != SCARD_S_SUCCESS) { log_printf(LOG_ERROR,"Failed to query reader status before connecting: %s (error 0x%08x).", pcsc_stringify_error(pcsc->status), pcsc->status ); return 0; } progress = ui_inprogress_new("Connection","Waiting for the reader to connect to a card."); while ((reader_state.dwEventState & SCARD_STATE_PRESENT)==0) { reader_state.dwCurrentState = reader_state.dwEventState; if (((counter++)%30)==0) { log_printf(LOG_INFO,"Waiting for card to be present (current state: %s)...", pcsc_stringify_state(reader_state.dwEventState)); } if (!ui_inprogress_pulse(progress)) { log_printf(LOG_ERROR,"Connection aborted by user"); ui_inprogress_free(progress); pcsc->status = 0x6FFF; return 0; } pcsc->status = SCardGetStatusChange(pcsc->hcontext,100,&reader_state,1); if ((pcsc->status!=(LONG)SCARD_S_SUCCESS) && (pcsc->status!=(LONG)SCARD_E_TIMEOUT)) { log_printf(LOG_ERROR,"Failed to query reader status change before connecting: %s (error 0x%08x/%08x).", pcsc_stringify_error(pcsc->status), pcsc->status, SCARD_E_TIMEOUT ); return 0; } } ui_inprogress_free(progress); log_printf(LOG_DEBUG,"Attempting to connect to '%s'",cr->name); pcsc->status = SCardConnect(pcsc->hcontext, cr->name+7, /* SCARD_SHARE_EXCLUSIVE, */ SCARD_SHARE_SHARED, prefered_protocol, &(pcsc->hcard), &(cr->protocol)); if (pcsc->status!=SCARD_S_SUCCESS) { log_printf(LOG_ERROR,"Connection failed: %s (error 0x%08x).", pcsc_stringify_error(pcsc->status), pcsc->status ); return 0; } if (SCardGetAttrib(pcsc->hcard,SCARD_ATTR_MAXINPUT,(LPBYTE)&attr_maxinput,(LPDWORD)&attr_maxinput_len)==SCARD_S_SUCCESS) log_printf(LOG_INFO,"Reader maximum input length is %u bytes",attr_maxinput); else log_printf(LOG_DEBUG,"Could not determinate reader maximum input length"); log_printf(LOG_INFO,"Connection successful, protocol is %s",pcsc_stringify_protocol(cr->protocol)); cr->connected=1; return 1; }
int main(int argc, char *argv[]) { LONG rv; SCARDCONTEXT hContext; SCARDHANDLE hCard; char *reader; BYTE pbSendBuffer[1 + 1 + sizeof(nfc_connstring)]; DWORD dwSendLength; BYTE pbRecvBuffer[1]; DWORD dwActiveProtocol, dwRecvLength, dwReaders; char* mszReaders = NULL; if (argc == 1 || (argc == 2 && (strncmp(argv[1], "yes", strlen("yes")) == 0))) pbSendBuffer[0] = IFDNFC_SET_ACTIVE; else if (argc == 2 && (strncmp(argv[1], "no", strlen("no")) == 0)) pbSendBuffer[0] = IFDNFC_SET_INACTIVE; else if (argc == 2 && (strncmp(argv[1], "se", strlen("se")) == 0)) pbSendBuffer[0] = IFDNFC_SET_ACTIVE_SE; else if (argc == 2 && (strncmp(argv[1], "status", strlen("status")) == 0)) pbSendBuffer[0] = IFDNFC_GET_STATUS; else { printf("Usage: %s [yes|no|status]\n", argv[0]); exit(EXIT_FAILURE); } rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); if (rv < 0) goto pcsc_error; dwReaders = 0; // Ask how many bytes readers list take rv = SCardListReaders(hContext, NULL, NULL, &dwReaders); if (rv < 0) goto pcsc_error; // Then allocate and fill mszReaders mszReaders = malloc(dwReaders); rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders); if (rv < 0) goto pcsc_error; int l; for (reader = mszReaders; dwReaders > 0; l = strlen(reader) + 1, dwReaders -= l, reader += l) { if (strcmp(IFDNFC_READER_NAME, reader) <= 0) break; } if (dwReaders <= 0) { printf("Could not find a reader named: %s\n", IFDNFC_READER_NAME); rv = SCARD_E_NO_READERS_AVAILABLE; goto pcsc_error; } // TODO Handle multiple ifdnfc instance for multiple NFC device ? rv = SCardConnect(hContext, reader, SCARD_SHARE_DIRECT, 0, &hCard, &dwActiveProtocol); if (rv < 0) goto pcsc_error; if ((pbSendBuffer[0] == IFDNFC_SET_ACTIVE) || (pbSendBuffer[0] == IFDNFC_SET_ACTIVE_SE)) { const BYTE command = pbSendBuffer[0]; // To correctly probe NFC devices, ifdnfc must be disactivated first pbSendBuffer[0] = IFDNFC_SET_INACTIVE; dwSendLength = 1; rv = SCardControl(hCard, IFDNFC_CTRL_ACTIVE, pbSendBuffer, dwSendLength, pbRecvBuffer, sizeof(pbRecvBuffer), &dwRecvLength); if (rv < 0) { goto pcsc_error; } pbSendBuffer[0] = command; // Initialize libnfc nfc_init(NULL); // Allocate nfc_connstring array nfc_connstring connstrings[MAX_DEVICE_COUNT]; // List devices size_t szDeviceFound = nfc_list_devices(NULL, connstrings, MAX_DEVICE_COUNT); int connstring_index = -1; switch (szDeviceFound) { case 0: fprintf(stderr, "Unable to activate ifdnfc: no NFC device found.\n"); nfc_exit(NULL); goto error; break; case 1: // Only one NFC device available, so auto-select it! connstring_index = 0; break; default: // More than one available NFC devices, purpose a shell menu: printf("%d NFC devices found, please select one:\n", (int)szDeviceFound); for (size_t i = 0; i < szDeviceFound; i++) { nfc_device *pnd = nfc_open(NULL, connstrings[i]); if (pnd != NULL) { printf("[%d] %s\t (%s)\n", (int)i, nfc_device_get_name(pnd), nfc_device_get_connstring(pnd)); nfc_close(pnd); } else { fprintf(stderr, "nfc_open failed for %s\n", connstrings[i]); } } // libnfc isn't be needed anymore nfc_exit(NULL); printf(">> "); // Take user's choice if (1 != scanf("%d", &connstring_index)) { fprintf(stderr, "Value must an integer.\n"); goto error; } if ((connstring_index < 0) || (connstring_index >= (int)szDeviceFound)) { fprintf(stderr, "Invalid index selection.\n"); goto error; } break; } printf("Activating ifdnfc with \"%s\"...\n", connstrings[connstring_index]); // pbSendBuffer = { IFDNFC_SET_ACTIVE (1 byte), length (2 bytes), nfc_connstring (lenght bytes)} const uint16_t u16ConnstringLength = strlen(connstrings[connstring_index]) + 1; memcpy(pbSendBuffer + 1, &u16ConnstringLength, sizeof(u16ConnstringLength)); memcpy(pbSendBuffer + 1 + sizeof(u16ConnstringLength), connstrings[connstring_index], u16ConnstringLength); dwSendLength = 1 + sizeof(u16ConnstringLength) + u16ConnstringLength; } else { // pbSendBuffer[0] != IFDNFC_SET_ACTIVE dwSendLength = 1; } rv = SCardControl(hCard, IFDNFC_CTRL_ACTIVE, pbSendBuffer, dwSendLength, pbRecvBuffer, sizeof(pbRecvBuffer), &dwRecvLength); if (rv < 0) { goto pcsc_error; } if (dwRecvLength < 1) { rv = SCARD_F_INTERNAL_ERROR; goto pcsc_error; } switch (pbRecvBuffer[0]) { case IFDNFC_IS_ACTIVE: { uint16_t u16ConnstringLength; if (dwRecvLength < (1 + sizeof(u16ConnstringLength))) { rv = SCARD_F_INTERNAL_ERROR; goto pcsc_error; } memcpy(&u16ConnstringLength, pbRecvBuffer + 1, sizeof(u16ConnstringLength)); if ((dwRecvLength - (1 + sizeof(u16ConnstringLength))) != u16ConnstringLength) { rv = SCARD_F_INTERNAL_ERROR; goto pcsc_error; } nfc_connstring connstring; memcpy(connstring, pbRecvBuffer + 1 + sizeof(u16ConnstringLength), u16ConnstringLength); printf("%s is active using %s.\n", IFDNFC_READER_NAME, connstring); } break; case IFDNFC_IS_INACTIVE: printf("%s is inactive.\n", IFDNFC_READER_NAME); break; default: rv = SCARD_F_INTERNAL_ERROR; goto pcsc_error; } rv = SCardDisconnect(hCard, SCARD_LEAVE_CARD); if (rv < 0) goto pcsc_error; free(mszReaders); exit(EXIT_SUCCESS); pcsc_error: puts(pcsc_stringify_error(rv)); error: if (mszReaders) free(mszReaders); exit(EXIT_FAILURE); }
void SCardReader::run() { SCARDCONTEXT context; SCARDHANDLE cardHandle; DWORD activeProtocol; DWORD oldEventState; LONG erv; erv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &context); if (SCARD_S_SUCCESS == erv) { LONG crv; crv = SCardConnect(context, (LPCSTR) m_name, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &cardHandle, &activeProtocol); do { if (SCARD_S_SUCCESS == crv) { SCARD_IO_REQUEST ioRecvPci; BYTE recvBuffer[32]; BYTE sendBuffer[] = {0xFF, 0xCA, 0x00, 0x00, 0x00}; DWORD recvLength = sizeof(recvBuffer); LONG trv; trv = SCardTransmit(cardHandle, SCARD_PCI_T0, sendBuffer, sizeof(sendBuffer),&ioRecvPci, recvBuffer, &recvLength); if (SCARD_S_SUCCESS == trv) { if (recvLength == 6 && recvBuffer[4] == 0x90 && recvBuffer[5] == 0x00) m_cardid = (int)recvBuffer[0] | (int)recvBuffer[1] << 8 | (int)recvBuffer[2] << 16 | (int)recvBuffer[3] << 24; std::cout << m_cardid << " card inserted." << std::endl; if (m_mode == TallyMode) // m_mode(DriverMode) 初始化为DriverMode { //load authentication key recvLength = sizeof(recvBuffer); BYTE loadKey[] = {0xFF, 0x82, 0x00, 0x00, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; trv = SCardTransmit(cardHandle, SCARD_PCI_T0, loadKey, sizeof(loadKey), &ioRecvPci, recvBuffer, &recvLength); if (SCARD_S_SUCCESS == trv && recvLength == 2 && recvBuffer[0] == 0x90 && recvBuffer[1] == 0x00) { //authentication key recvLength = sizeof(recvBuffer); BYTE authentication[] = {0xFF, 0x86, 0x00, 0x00, 0x05, 0x01, 0x00, 0x08, 0x60, 0x00}; trv = SCardTransmit(cardHandle, SCARD_PCI_T0, authentication, sizeof(authentication), &ioRecvPci, recvBuffer, &recvLength); if (SCARD_S_SUCCESS == trv && recvLength == 2 && recvBuffer[0] == 0x90 && recvBuffer[1] == 0x00) { //read binary recvLength = sizeof(recvBuffer); BYTE read[] = {0xFF, 0xB0, 0x00, 0x08, 0x10}; trv = SCardTransmit(cardHandle, SCARD_PCI_T0, read, sizeof(read), &ioRecvPci, recvBuffer, &recvLength); if (SCARD_S_SUCCESS == trv && recvLength == 18 && recvBuffer[16] == 0x90 && recvBuffer[17] == 0x00) { QByteArray array((const char *)recvBuffer, 16); emit dataReady(QString::number(m_cardid), array); } else std::cerr << m_name << " : " << pcsc_stringify_error(trv) << std::endl; } else std::cerr << m_name << " : " << pcsc_stringify_error(trv) << std::endl; } else std::cerr << m_name << " : " << pcsc_stringify_error(trv) << std::endl; } else emit inserted(QString::number(m_cardid)); } else if (SCARD_E_NO_SMARTCARD == trv) std::cerr << m_name << " : " << pcsc_stringify_error(trv) << std::endl; else { std::cerr << m_name << " : " << pcsc_stringify_error(trv) << std::endl; break; } (void) SCardDisconnect(cardHandle, SCARD_RESET_CARD); } if (SCARD_S_SUCCESS == crv || SCARD_E_NO_SMARTCARD == crv) { SCARD_READERSTATE readerStates; LONG grv; readerStates.szReader = m_name; readerStates.dwCurrentState = SCARD_STATE_UNAWARE; grv = SCardGetStatusChange(context, INFINITE, &readerStates, 1); oldEventState = readerStates.dwEventState; do { if (SCARD_S_SUCCESS == grv) { if (readerStates.dwEventState != oldEventState) { //card inserted if ((SCARD_STATE_CHANGED & readerStates.dwEventState) && (SCARD_STATE_PRESENT & readerStates.dwEventState)) break; //card removed if ((SCARD_STATE_CHANGED & readerStates.dwEventState) && (SCARD_STATE_EMPTY & readerStates.dwEventState)) { removed(QString::number(m_cardid)); std::cout << m_cardid << " card removed." << std::endl; } } else QThread::usleep(500); } else if (SCARD_E_TIMEOUT == grv) QThread::sleep(1); else break; oldEventState = readerStates.dwEventState; readerStates.szReader = m_name; readerStates.dwCurrentState = SCARD_STATE_UNAWARE; grv = SCardGetStatusChange(context, INFINITE, &readerStates, 1); } while (true); //quit if fatal error occurs if (SCARD_S_SUCCESS != grv) break; } else { std::cerr << m_name << " : " << pcsc_stringify_error(crv) << std::endl; break; } crv = SCardConnect(context, (LPCSTR) m_name, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &cardHandle, &activeProtocol); } while(true); } else std::cerr << m_name << " : " << pcsc_stringify_error(erv) << std::endl; std::cout << m_name << " deamon thread has exit." << std::endl; }
int main (int argc, const char *argv[]) { char *pin = 0; char *chal = 0; char *reader = 0; char *amount = 0; int getid = 0; int getotp = 0; int readernum = 0; int debug = 0; int listreader = 0; int hyphen = 0; int res; char c; SCARDCONTEXT ctx; SCARDHANDLE card; BYTE atr[MAX_ATR_SIZE]; DWORD atrlen; DWORD state; DWORD proto; DWORD temp; SCARD_IO_REQUEST recvpci; DWORD buflen; BYTE buf[256], cmd[256]; poptContext optCon; // context for parsing command-line options const struct poptOption optionsTable[] = { {"id", 'i', POPT_ARG_NONE, &getid, 0, "Report card ID", 0}, {"pin", 'p', POPT_ARG_STRING, &pin, 0, "PIN", "6 to 12 digits"}, {"otp", 'o', POPT_ARG_NONE, &getotp, 0, "Get OTP", 0}, {"reference", 'c', POPT_ARG_STRING, &chal, 0, "Challenge/response or account reference", "Up to 8 digit reference/account"}, {"amount", 'a', POPT_ARG_STRING, &amount, 0, "", "Amount pounds.pence"}, {"reader", 'r', POPT_ARG_INT, &readernum, 0, "Which reader to use", "Index number"}, {"list", 'l', POPT_ARG_NONE, &listreader, 0, "List readers", 0}, {"hyphen", 'h', POPT_ARG_NONE, &hyphen, 0, "Hyphenate OTP or C/R responses", 0}, {"debug", 'v', POPT_ARG_NONE, &debug, 0, "Debug output", 0}, POPT_AUTOHELP {NULL, 0, 0, NULL, 0} }; optCon = poptGetContext (NULL, argc, argv, optionsTable, 0); //poptSetOtherOptionHelp (optCon, ""); /* Now do options processing, get portname */ if ((c = poptGetNextOpt (optCon)) < -1) { /* an error occurred during option processing */ fprintf (stderr, "%s: %s\n", poptBadOption (optCon, POPT_BADOPTION_NOALIAS), poptStrerror (c)); return 1; } if (poptPeekArg (optCon)) { poptPrintUsage (optCon, stderr, 0); return 2; } if ((res = SCardEstablishContext (SCARD_SCOPE_SYSTEM, NULL, NULL, &ctx)) != SCARD_S_SUCCESS) errx (1, "Can't establish context for reading cards (%s)", pcsc_stringify_error (res)); { // list the readers int rn = 0; char *r, *e; if ((res = SCardListReaders (ctx, NULL, NULL, &temp)) != SCARD_S_SUCCESS) errx (1, "Cannot get reader list (%s)", pcsc_stringify_error (res)); if (!(r = malloc (temp))) errx (1, "Cannot allocated %d bytes for reader list", (int) temp); if ((res = SCardListReaders (ctx, NULL, r, &temp)) != SCARD_S_SUCCESS) errx (1, "Cannot list readers (%s)", pcsc_stringify_error (res)); e = r + temp; while (*r && r < e) { if (rn == readernum) reader = r; if (listreader) printf ("%d: %s\n", rn, r); r += strlen (r) + 1; rn++; } // not freed as reader is pointer into r. } if (!reader) errx (1, "Reader %d does not exist", readernum); if (debug) fprintf (stderr, "Reader: %s\n", reader); // connect to card if ((res = SCardConnect (ctx, reader, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &card, &proto)) != SCARD_S_SUCCESS) errx (1, "Cannot connect to %s (%s)", reader, pcsc_stringify_error (res)); if (debug) fprintf (stderr, "Active protocol %X\n", (int) proto); if ((res = SCardBeginTransaction (card)) != SCARD_S_SUCCESS) errx (1, "Cannot start transaction (%s)", pcsc_stringify_error (res)); atrlen = sizeof (atr); if ((res = SCardStatus (card, 0, &temp, &state, &proto, atr, &atrlen)) != SCARD_S_SUCCESS) errx (1, "Cannot get card status (%s)", pcsc_stringify_error (res)); if (debug) fprintf (stderr, "ATR len %d state %X\n", (int) atrlen, (int) state); { // get basic data BYTE datareq[] = { 0x00, 0xA4, 0x04, 0x00, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x80, 0x02 }; // initial data request buflen = sizeof (buf); if (debug) dump ('>', sizeof (datareq), datareq); if ((res = SCardTransmit (card, SCARD_PCI_T0, datareq, sizeof (datareq), &recvpci, buf, &buflen)) != SCARD_S_SUCCESS) errx (1, "Failed to send initial request for data (%s)", pcsc_stringify_error (res)); if (debug) dump ('<', buflen, buf); if (buflen != 2 || buf[0] != 0x61) errx (1, "Unexpected response to data request"); } cmd[0] = 0x0; cmd[1] = 0xC0; cmd[2] = 0; cmd[3] = 0; cmd[4] = buf[1]; buflen = sizeof (buf); if (debug) dump ('>', 5, cmd); if ((res = SCardTransmit (card, SCARD_PCI_T0, cmd, 5, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS) errx (1, "Failed get initial data (%s)", pcsc_stringify_error (res)); if (debug) dump ('<', buflen, buf); if (buflen != cmd[4] + 2) errx (1, "Did not get right data length %d!=%d", (int) buflen, cmd[4]); cmd[0] = 0x80; cmd[1] = 0xA8; cmd[2] = 0x00; cmd[3] = 0x00; cmd[4] = 0x02; cmd[5] = 0x83; cmd[6] = 0x00; buflen = sizeof (buf); if (debug) dump ('>', 7, cmd); if ((res = SCardTransmit (card, SCARD_PCI_T0, cmd, 7, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS) errx (1, "Failed get data (%s)", pcsc_stringify_error (res)); if (debug) dump ('<', buflen, buf); if (buflen != 2 || buf[0] != 0x61) errx (1, "Bad response\n"); cmd[0] = 0x00; cmd[1] = 0xC0; cmd[2] = 0x00; cmd[3] = 0x00; cmd[4] = buf[1]; buflen = sizeof (buf); if (debug) dump ('>', 5, cmd); if ((res = SCardTransmit (card, SCARD_PCI_T0, cmd, 5, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS) errx (1, "Failed to send data (%s)", pcsc_stringify_error (res)); if (debug) dump ('<', buflen, buf); if (getid) { // card number int n = 0; cmd[0] = 0x00; cmd[1] = 0xB2; cmd[2] = 0x02; cmd[3] = 0x0C; cmd[4] = 0x00; buflen = sizeof (buf); if (debug) dump ('>', 5, cmd); if ((res = SCardTransmit (card, SCARD_PCI_T0, cmd, 5, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS) errx (1, "Failed to send data (%s)", pcsc_stringify_error (res)); if (debug) dump ('<', buflen, buf); if (buflen != 2 || buf[0] != 0x6C) errx (1, "Unexpected response to data request"); cmd[4] = buf[1]; buflen = sizeof (buf); if (debug) dump ('>', 5, cmd); if ((res = SCardTransmit (card, SCARD_PCI_T0, cmd, 5, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS) errx (1, "Failed get initial data (%s)", pcsc_stringify_error (res)); if (debug) dump ('<', buflen, buf); if (buflen != cmd[4] + 2 || buflen < 12) errx (1, "Did not get right data length %d!=%d", (int) buflen, cmd[4]); for (n = 4; n < 12; n++) printf ("%02X", buf[n]); printf ("\n"); } // send PIN if needed if (pin && (getotp || chal || amount || debug)) { // send PIN char *p = pin; int n = 0; cmd[0] = 0; cmd[1] = 0x20; cmd[2] = 0x00; cmd[3] = 0x80; cmd[4] = 8; cmd[5] = 0x24; while (*p && n < 14) { if (isdigit (*p)) { cmd[6 + n / 2] = (cmd[6 + n / 2] << 4) + (*p - '0'); n++; } p++; } while (n < 14) { cmd[6 + n / 2] = (cmd[6 + n / 2] << 4) + 0xF; n++; } buflen = sizeof (buf); if (debug) dump ('>', 13, cmd); if ((res = SCardTransmit (card, SCARD_PCI_T0, cmd, 13, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS) errx (1, "Failed to send PIN (%s)", pcsc_stringify_error (res)); if (debug) dump ('<', buflen, buf); if (buflen != 2 || buf[0] != 0x90 || buf[1]) errx (1, "PIN failed"); } if (getotp || chal || amount) { // OTP unsigned char req[29] = { 0 }; req[14] = 0x80; req[21] = req[22] = req[23] = 1; if (chal) { int n = 0, p; for (p = 0; chal[p]; p++) if (isdigit (chal[p])) n++; for (p = 0; chal[p] && n; p++) if (isdigit (chal[p])) { n--; if (n < 8) req[28 - n / 2] |= ((chal[p] & 0xF) << ((n & 1) ? 4 : 0)); } } if (amount) { int n = 0, p; for (p = 0; amount[p]; p++) if (isdigit (amount[p])) n++; for (p = 0; amount[p] && n; p++) if (isdigit (amount[p])) { n--; if (n < 12) req[5 - n / 2] |= ((amount[p] & 0xF) << ((n & 1) ? 4 : 0)); } } buflen = sizeof (buf); buf[0] = 0x80; buf[1] = 0xAE; buf[2] = 0x80; buf[3] = 0x00; buf[4] = sizeof (req); memcpy (buf + 5, req, sizeof (req)); if (debug) dump ('>', sizeof (req) + 5, buf); if ((res = SCardTransmit (card, SCARD_PCI_T0, buf, sizeof (req) + 5, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS) errx (1, "Failed to send OTP request (%s)", pcsc_stringify_error (res)); if (debug) dump ('<', buflen, buf); if (buflen != 2 || buf[0] != 0x61) errx (1, "Failed to get OTP"); cmd[0] = 0x00; cmd[1] = 0xC0; cmd[2] = 0x00; cmd[3] = 0x00; cmd[4] = buf[1]; buflen = sizeof (buf); if (debug) dump ('>', 5, cmd); if ((res = SCardTransmit (card, SCARD_PCI_T0, cmd, 5, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS) errx (1, "Failed to send OTP request (%s)", pcsc_stringify_error (res)); if (debug) dump ('<', buflen, buf); if (buflen != 22) errx (1, "Bad OTP response"); { unsigned long res = ((1 << 25) | (buf[4] << 17) | ((buf[10] & 0x01) << 16) | (buf[11] << 8) | buf[12]); printf ("%08lu\n", res); } // Advance OTP to next number buf[0] = 0x80; buf[1] = 0xAE; buf[2] = 0x00; buf[3] = 0x00; buf[4] = sizeof (req) + 2; buf[5] = 0x5A; buf[6] = 0x33; memcpy (buf + 7, req, sizeof (req)); buflen = sizeof (buf); if (debug) dump ('>', sizeof (req) + 7, buf); if ((res = SCardTransmit (card, SCARD_PCI_T0, buf, sizeof (req) + 7, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS) errx (1, "Failed to send OTP request (%s)", pcsc_stringify_error (res)); if (debug) dump ('<', buflen, buf); if (buflen != 2 || buf[0] != 0x61) errx (1, "Failed to get OTP"); cmd[0] = 0x00; cmd[1] = 0xC0; cmd[2] = 0x00; buflen = sizeof (buf); if (debug) dump ('>', 5, cmd); if ((res = SCardTransmit (card, SCARD_PCI_T0, cmd, 5, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS) errx (1, "Failed to send OTP request (%s)", pcsc_stringify_error (res)); if (debug) dump ('<', buflen, buf); } // Done if ((res = SCardEndTransaction (card, SCARD_UNPOWER_CARD)) != SCARD_S_SUCCESS) errx (1, "Cannot end transaction (%s)", pcsc_stringify_error (res)); if ((res = SCardReleaseContext (ctx)) != SCARD_S_SUCCESS) errx (1, "Cant release context (%s)", pcsc_stringify_error (res)); return 0; }