| 22 |
#include <stdio.h> |
#include <stdio.h> |
| 23 |
#include <string.h> |
#include <string.h> |
| 24 |
#include <stdlib.h> |
#include <stdlib.h> |
| 25 |
|
#include <arpa/inet.h> |
| 26 |
#include "misc.h" |
#include "misc.h" |
| 27 |
#include <pcsclite.h> |
#include <pcsclite.h> |
| 28 |
#include <ifdhandler.h> |
#include <ifdhandler.h> |
| 60 |
static void init_driver(void); |
static void init_driver(void); |
| 61 |
static void extra_egt(ATR_t *atr, _ccid_descriptor *ccid_desc, DWORD Protocol); |
static void extra_egt(ATR_t *atr, _ccid_descriptor *ccid_desc, DWORD Protocol); |
| 62 |
static char find_baud_rate(unsigned int baudrate, unsigned int *list); |
static char find_baud_rate(unsigned int baudrate, unsigned int *list); |
| 63 |
static unsigned int T0_card_timeout(double f, double d, int TC1, int TC2, |
static unsigned int T0_card_timeout(double f, double d, int TC1, int TC2, |
| 64 |
int clock_frequency); |
int clock_frequency); |
| 65 |
static unsigned int T1_card_timeout(double f, double d, int TC1, int BWI, |
static unsigned int T1_card_timeout(double f, double d, int TC1, int BWI, |
| 66 |
int CWI, int clock_frequency); |
int CWI, int clock_frequency); |
| 99 |
ReleaseReaderIndex(reader_index); |
ReleaseReaderIndex(reader_index); |
| 100 |
} |
} |
| 101 |
else |
else |
| 102 |
|
{ |
| 103 |
/* Maybe we have a special treatment for this reader */ |
/* Maybe we have a special treatment for this reader */ |
| 104 |
ccid_open_hack(reader_index); |
ccid_open_hack(reader_index); |
| 105 |
|
|
| 106 |
|
/* Try to access the reader */ |
| 107 |
|
/* This "warm up" sequence is sometimes needed when pcscd is |
| 108 |
|
* restarted with the reader already connected. We get some |
| 109 |
|
* "usb_bulk_read: Resource temporarily unavailable" on the first |
| 110 |
|
* few tries. It is an empirical hack */ |
| 111 |
|
if ((IFD_COMMUNICATION_ERROR == IFDHICCPresence(Lun)) |
| 112 |
|
&& (IFD_COMMUNICATION_ERROR == IFDHICCPresence(Lun)) |
| 113 |
|
&& (IFD_COMMUNICATION_ERROR == IFDHICCPresence(Lun))) |
| 114 |
|
{ |
| 115 |
|
DEBUG_CRITICAL("failed"); |
| 116 |
|
return_value = IFD_COMMUNICATION_ERROR; |
| 117 |
|
|
| 118 |
|
/* release the allocated reader_index */ |
| 119 |
|
ReleaseReaderIndex(reader_index); |
| 120 |
|
} |
| 121 |
|
} |
| 122 |
|
|
| 123 |
#ifdef HAVE_PTHREAD |
#ifdef HAVE_PTHREAD |
| 124 |
pthread_mutex_unlock(&ifdh_context_mutex); |
pthread_mutex_unlock(&ifdh_context_mutex); |
| 125 |
#endif |
#endif |
| 322 |
} |
} |
| 323 |
break; |
break; |
| 324 |
|
|
| 325 |
|
case SCARD_ATTR_VENDOR_IFD_VERSION: |
| 326 |
|
/* Vendor-supplied interface device version (DWORD in the form |
| 327 |
|
* 0xMMmmbbbb where MM = major version, mm = minor version, and |
| 328 |
|
* bbbb = build number). */ |
| 329 |
|
*Length = sizeof(DWORD); |
| 330 |
|
if (Value) |
| 331 |
|
*(DWORD *)Value = CCID_VERSION; |
| 332 |
|
break; |
| 333 |
|
|
| 334 |
|
case SCARD_ATTR_VENDOR_NAME: |
| 335 |
|
#define VENDOR_NAME "Ludovic Rousseau" |
| 336 |
|
*Length = sizeof(VENDOR_NAME); |
| 337 |
|
if (Value) |
| 338 |
|
memcpy(Value, VENDOR_NAME, sizeof(VENDOR_NAME)); |
| 339 |
|
break; |
| 340 |
|
|
| 341 |
|
case SCARD_ATTR_MAXINPUT: |
| 342 |
|
*Length = sizeof(uint32_t); |
| 343 |
|
if (Value) |
| 344 |
|
*(uint32_t *)Value = get_ccid_descriptor(reader_index) -> dwMaxCCIDMessageLength -10; |
| 345 |
|
break; |
| 346 |
|
|
| 347 |
default: |
default: |
| 348 |
return IFD_ERROR_TAG; |
return IFD_ERROR_TAG; |
| 349 |
} |
} |
| 824 |
RESPONSECODE return_value = IFD_SUCCESS; |
RESPONSECODE return_value = IFD_SUCCESS; |
| 825 |
unsigned char pcbuffer[RESP_BUF_SIZE]; |
unsigned char pcbuffer[RESP_BUF_SIZE]; |
| 826 |
int reader_index; |
int reader_index; |
| 827 |
|
char *actions[] = { "PowerUp", "PowerDown", "Reset" }; |
| 828 |
|
|
| 829 |
DEBUG_INFO2("lun: %X", Lun); |
DEBUG_INFO3("lun: %X, action: %s", Lun, actions[Action-IFD_POWER_UP]); |
| 830 |
|
|
| 831 |
/* By default, assume it won't work :) */ |
/* By default, assume it won't work :) */ |
| 832 |
*AtrLength = 0; |
*AtrLength = 0; |
| 949 |
|
|
| 950 |
EXTERNAL RESPONSECODE IFDHControl(DWORD Lun, DWORD dwControlCode, |
EXTERNAL RESPONSECODE IFDHControl(DWORD Lun, DWORD dwControlCode, |
| 951 |
PUCHAR TxBuffer, DWORD TxLength, PUCHAR RxBuffer, DWORD RxLength, |
PUCHAR TxBuffer, DWORD TxLength, PUCHAR RxBuffer, DWORD RxLength, |
| 952 |
PDWORD pdwBytesReturned) |
PDWORD pdwBytesReturned) |
| 953 |
{ |
{ |
| 954 |
/* |
/* |
| 955 |
* This function performs a data exchange with the reader (not the |
* This function performs a data exchange with the reader (not the |
| 996 |
} |
} |
| 997 |
|
|
| 998 |
/* Implement the PC/SC v2.1.2 Part 10 IOCTL mechanism */ |
/* Implement the PC/SC v2.1.2 Part 10 IOCTL mechanism */ |
| 999 |
|
|
| 1000 |
/* Query for features */ |
/* Query for features */ |
| 1001 |
if (CM_IOCTL_GET_FEATURE_REQUEST == dwControlCode) |
if (CM_IOCTL_GET_FEATURE_REQUEST == dwControlCode) |
| 1002 |
{ |
{ |
| 1013 |
{ |
{ |
| 1014 |
pcsc_tlv -> tag = FEATURE_VERIFY_PIN_DIRECT; |
pcsc_tlv -> tag = FEATURE_VERIFY_PIN_DIRECT; |
| 1015 |
pcsc_tlv -> length = 0x04; /* always 0x04 */ |
pcsc_tlv -> length = 0x04; /* always 0x04 */ |
| 1016 |
pcsc_tlv -> value = IOCTL_FEATURE_VERIFY_PIN_DIRECT; |
pcsc_tlv -> value = htonl(IOCTL_FEATURE_VERIFY_PIN_DIRECT); |
| 1017 |
|
|
| 1018 |
pcsc_tlv++; |
pcsc_tlv++; |
| 1019 |
iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); |
iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); |
| 1020 |
} |
} |
| 1021 |
|
|
| 1022 |
if (get_ccid_descriptor(reader_index) -> bPINSupport |
if (get_ccid_descriptor(reader_index) -> bPINSupport |
| 1023 |
& CCID_CLASS_PIN_MODIFY) |
& CCID_CLASS_PIN_MODIFY) |
| 1024 |
{ |
{ |
| 1025 |
pcsc_tlv -> tag = FEATURE_MODIFY_PIN_DIRECT; |
pcsc_tlv -> tag = FEATURE_MODIFY_PIN_DIRECT; |
| 1026 |
pcsc_tlv -> length = 0x04; /* always 0x04 */ |
pcsc_tlv -> length = 0x04; /* always 0x04 */ |
| 1027 |
pcsc_tlv -> value = IOCTL_FEATURE_MODIFY_PIN_DIRECT; |
pcsc_tlv -> value = htonl(IOCTL_FEATURE_MODIFY_PIN_DIRECT); |
| 1028 |
|
|
| 1029 |
pcsc_tlv++; |
pcsc_tlv++; |
| 1030 |
iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); |
iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); |
| 1109 |
switch (pcbuffer[7] & CCID_ICC_STATUS_MASK) /* bStatus */ |
switch (pcbuffer[7] & CCID_ICC_STATUS_MASK) /* bStatus */ |
| 1110 |
{ |
{ |
| 1111 |
case CCID_ICC_PRESENT_ACTIVE: |
case CCID_ICC_PRESENT_ACTIVE: |
|
case CCID_ICC_PRESENT_INACTIVE: |
|
| 1112 |
return_value = IFD_ICC_PRESENT; |
return_value = IFD_ICC_PRESENT; |
| 1113 |
/* use default slot */ |
/* use default slot */ |
| 1114 |
break; |
break; |
| 1115 |
|
|
| 1116 |
|
case CCID_ICC_PRESENT_INACTIVE: |
| 1117 |
|
if ((CcidSlots[reader_index].bPowerFlags == POWERFLAGS_RAZ) |
| 1118 |
|
|| (CcidSlots[reader_index].bPowerFlags & MASK_POWERFLAGS_PDWN)) |
| 1119 |
|
/* the card was previously absent */ |
| 1120 |
|
return_value = IFD_ICC_PRESENT; |
| 1121 |
|
else |
| 1122 |
|
{ |
| 1123 |
|
/* the card was previously present but has been |
| 1124 |
|
* removed and inserted between two consecutive |
| 1125 |
|
* IFDHICCPresence() calls */ |
| 1126 |
|
CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ; |
| 1127 |
|
return_value = IFD_ICC_NOT_PRESENT; |
| 1128 |
|
} |
| 1129 |
|
break; |
| 1130 |
|
|
| 1131 |
case CCID_ICC_ABSENT: |
case CCID_ICC_ABSENT: |
| 1132 |
/* Reset ATR buffer */ |
/* Reset ATR buffer */ |
| 1133 |
CcidSlots[reader_index].nATRLength = 0; |
CcidSlots[reader_index].nATRLength = 0; |
| 1153 |
|
|
| 1154 |
unsigned char res[10]; |
unsigned char res[10]; |
| 1155 |
unsigned int length_res = sizeof(res); |
unsigned int length_res = sizeof(res); |
| 1156 |
|
RESPONSECODE ret; |
| 1157 |
|
|
| 1158 |
/* if DEBUG_LEVEL_PERIODIC is not set we remove DEBUG_LEVEL_COMM */ |
/* if DEBUG_LEVEL_PERIODIC is not set we remove DEBUG_LEVEL_COMM */ |
| 1159 |
oldLogLevel = LogLevel; |
oldLogLevel = LogLevel; |
| 1160 |
if (! (LogLevel & DEBUG_LEVEL_PERIODIC)) |
if (! (LogLevel & DEBUG_LEVEL_PERIODIC)) |
| 1161 |
LogLevel &= ~DEBUG_LEVEL_COMM; |
LogLevel &= ~DEBUG_LEVEL_COMM; |
| 1162 |
|
|
| 1163 |
CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res); |
ret = CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res); |
| 1164 |
|
|
| 1165 |
/* set back the old LogLevel */ |
/* set back the old LogLevel */ |
| 1166 |
LogLevel = oldLogLevel; |
LogLevel = oldLogLevel; |
| 1167 |
|
|
| 1168 |
|
if (ret != IFD_SUCCESS) |
| 1169 |
|
{ |
| 1170 |
|
DEBUG_INFO("CmdEscape failed"); |
| 1171 |
|
/* simulate a card absent */ |
| 1172 |
|
res[0] = 0; |
| 1173 |
|
} |
| 1174 |
|
|
| 1175 |
if (0x01 == res[0]) |
if (0x01 == res[0]) |
| 1176 |
return_value = IFD_ICC_PRESENT; |
return_value = IFD_ICC_PRESENT; |
| 1177 |
else |
else |
| 1315 |
for (i=2; i<ATR_MAX_PROTOCOLS; i++) |
for (i=2; i<ATR_MAX_PROTOCOLS; i++) |
| 1316 |
{ |
{ |
| 1317 |
/* CWI >= 2 ? */ |
/* CWI >= 2 ? */ |
| 1318 |
if (atr->ib[i][ATR_INTERFACE_BYTE_TB].present && |
if (atr->ib[i][ATR_INTERFACE_BYTE_TB].present && |
| 1319 |
((atr->ib[i][ATR_INTERFACE_BYTE_TB].value & 0x0F) >= 2)) |
((atr->ib[i][ATR_INTERFACE_BYTE_TB].value & 0x0F) >= 2)) |
| 1320 |
{ |
{ |
| 1321 |
/* Init TC1 */ |
/* Init TC1 */ |
| 1380 |
* Terminal: Smart card: |
* Terminal: Smart card: |
| 1381 |
* 5 bytes header cmd -> |
* 5 bytes header cmd -> |
| 1382 |
* <- Procedure byte + 256 data bytes + SW1-SW2 |
* <- Procedure byte + 256 data bytes + SW1-SW2 |
| 1383 |
* = 5 EGT + 1 WWT + 259 WWT |
* = 5 EGT + 1 WWT + 259 WWT |
| 1384 |
*/ |
*/ |
| 1385 |
|
|
| 1386 |
/* clock_frequency is in kHz so the times are in milliseconds and not |
/* clock_frequency is in kHz so the times are in milliseconds and not |
| 1426 |
/* Timeout applied on ISO in + ISO out card exchange |
/* Timeout applied on ISO in + ISO out card exchange |
| 1427 |
* |
* |
| 1428 |
* Timeout is the sum of: |
* Timeout is the sum of: |
| 1429 |
* - ISO in delay between leading edge of the first character sent by the |
* - ISO in delay between leading edge of the first character sent by the |
| 1430 |
* interface device and the last one (NAD PCB LN APDU CKS) = 260 EGT, |
* interface device and the last one (NAD PCB LN APDU CKS) = 260 EGT, |
| 1431 |
* - delay between ISO in and ISO out = BWT, |
* - delay between ISO in and ISO out = BWT, |
| 1432 |
* - ISO out delay between leading edge of the first character sent by the |
* - ISO out delay between leading edge of the first character sent by the |
| 1433 |
* card and the last one (NAD PCB LN DATAS CKS) = 260 CWT. |
* card and the last one (NAD PCB LN DATAS CKS) = 260 CWT. |
| 1434 |
*/ |
*/ |
| 1435 |
|
|
| 1436 |
/* clock_frequency is in kHz so the times are in milliseconds and not |
/* clock_frequency is in kHz so the times are in milliseconds and not |