/***************************************************************************** * * set_gemalto_firmware_features * ****************************************************************************/ static void set_gemalto_firmware_features(unsigned int reader_index) { _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); struct GEMALTO_FIRMWARE_FEATURES *gf_features; gf_features = malloc(sizeof(struct GEMALTO_FIRMWARE_FEATURES)); if (gf_features) { unsigned char cmd[] = { 0x6A }; /* GET_FIRMWARE_FEATURES command id */ unsigned int len_features = sizeof *gf_features; RESPONSECODE ret; ret = CmdEscape(reader_index, cmd, sizeof cmd, (unsigned char*)gf_features, &len_features, 0); if ((IFD_SUCCESS == ret) && (len_features == sizeof *gf_features)) { /* Command is supported if it succeeds at CCID level */ /* and returned size matches our expectation */ ccid_descriptor->gemalto_firmware_features = gf_features; #ifndef NO_LOG dump_gemalto_firmware_features(gf_features); #endif } else { /* Command is not supported, let's free allocated memory */ free(gf_features); DEBUG_INFO3("GET_FIRMWARE_FEATURES failed: " DWORD_D ", len=%d", ret, len_features); } } } /* set_gemalto_firmware_features */
/***************************************************************************** * * ccid_open_hack_post * ****************************************************************************/ int ccid_open_hack_post(unsigned int reader_index) { _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); RESPONSECODE return_value = IFD_SUCCESS; switch (ccid_descriptor->readerID) { case GEMPCKEY: case GEMPCTWIN: /* Reader announces TPDU but can do APDU (EMV in fact) */ if (DriverOptions & DRIVER_OPTION_GEMPC_TWIN_KEY_APDU) { unsigned char cmd[] = { 0x1F, 0x02 }; unsigned char res[10]; unsigned int length_res = sizeof(res); if (CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res, 0) == IFD_SUCCESS) { ccid_descriptor->dwFeatures &= ~CCID_CLASS_EXCHANGE_MASK; ccid_descriptor->dwFeatures |= CCID_CLASS_SHORT_APDU; } } break; case VEGAALPHA: case GEMPCPINPAD: /* load the l10n strings in the pinpad memory */ { #define L10N_HEADER_SIZE 5 #define L10N_STRING_MAX_SIZE 16 #define L10N_NB_STRING 10 unsigned char cmd[L10N_HEADER_SIZE + L10N_NB_STRING * L10N_STRING_MAX_SIZE]; unsigned char res[20]; unsigned int length_res = sizeof(res); int offset, i, j; const char *fr[] = { "Entrer PIN", "Nouveau PIN", "Confirmer PIN", "PIN correct", "PIN Incorrect !", "Delai depasse", "* essai restant", "Inserer carte", "Erreur carte", "PIN bloque" }; const char *de[] = { "PIN eingeben", "Neue PIN", "PIN bestatigen", "PIN korrect", "Falsche PIN !", "Zeit abgelaufen", "* Versuche ubrig", "Karte einstecken", "Fehler Karte", "PIN blockiert" }; const char *es[] = { "Introducir PIN", "Nuevo PIN", "Confirmar PIN", "PIN OK", "PIN Incorrecto !", "Tiempo Agotado", "* ensayos quedan", "Introducir Tarj.", "Error en Tarjeta", "PIN bloqueado" }; const char *it[] = { "Inserire PIN", "Nuovo PIN", "Confermare PIN", "PIN Corretto", "PIN Errato !", "Tempo scaduto", "* prove rimaste", "Inserire Carta", "Errore Carta", "PIN ostruito"}; const char *pt[] = { "Insira PIN", "Novo PIN", "Conf. novo PIN", "PIN OK", "PIN falhou!", "Tempo expirou", "* tentiv. restam", "Introduza cartao", "Erro cartao", "PIN bloqueado" }; const char *nl[] = { "Inbrengen code", "Nieuwe code", "Bevestig code", "Code aanvaard", "Foute code", "Time out", "* Nog Pogingen", "Kaart inbrengen", "Kaart fout", "Kaart blok" }; const char *tr[] = { "PIN Giriniz", "Yeni PIN", "PIN Onayala", "PIN OK", "Yanlis PIN", "Zaman Asimi", "* deneme kaldi", "Karti Takiniz", "Kart Hatasi", "Kart Kilitli" }; const char *en[] = { "Enter PIN", "New PIN", "Confirm PIN", "PIN OK", "Incorrect PIN!", "Time Out", "* retries left", "Insert Card", "Card Error", "PIN blocked" }; const char *lang; const char **l10n; #ifdef __APPLE__ CFArrayRef cfa; CFStringRef slang; /* Get the complete ordered list */ cfa = CFLocaleCopyPreferredLanguages(); /* Use the first/preferred language * As the driver is run as root we get the language * selected during install */ slang = CFArrayGetValueAtIndex(cfa, 0); /* CFString -> C string */ lang = CFStringGetCStringPtr(slang, kCFStringEncodingMacRoman); #else /* The other Unixes just use the LANG env variable */ lang = getenv("LANG"); #endif DEBUG_COMM2("Using lang: %s", lang); if (NULL == lang) l10n = en; else { if (0 == strncmp(lang, "fr", 2)) l10n = fr; else if (0 == strncmp(lang, "de", 2)) l10n = de; else if (0 == strncmp(lang, "es", 2)) l10n = es; else if (0 == strncmp(lang, "it", 2)) l10n = it; else if (0 == strncmp(lang, "pt", 2)) l10n = pt; else if (0 == strncmp(lang, "nl", 2)) l10n = nl; else if (0 == strncmp(lang, "tr", 2)) l10n = tr; else l10n = en; } #ifdef __APPLE__ /* Release the allocated array */ CFRelease(cfa); #endif offset = 0; cmd[offset++] = 0xB2; /* load strings */ cmd[offset++] = 0xA0; /* address of the memory */ cmd[offset++] = 0x00; /* address of the first byte */ cmd[offset++] = 0x4D; /* magic value */ cmd[offset++] = 0x4C; /* magic value */ /* for each string */ for (i=0; i<L10N_NB_STRING; i++) { /* copy the string */ for (j=0; l10n[i][j]; j++) cmd[offset++] = l10n[i][j]; /* pad with " " */ for (; j<L10N_STRING_MAX_SIZE; j++) cmd[offset++] = ' '; } (void)sleep(1); if (IFD_SUCCESS == CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res, DEFAULT_COM_READ_TIMEOUT)) { DEBUG_COMM("l10n string loaded successfully"); } else { DEBUG_COMM("Failed to load l10n strings"); return_value = IFD_COMMUNICATION_ERROR; } if (DriverOptions & DRIVER_OPTION_DISABLE_PIN_RETRIES) { /* disable VERIFY from reader */ const unsigned char cmd2[] = {0xb5, 0x00}; length_res = sizeof(res); if (IFD_SUCCESS == CmdEscape(reader_index, cmd2, sizeof(cmd2), res, &length_res, DEFAULT_COM_READ_TIMEOUT)) { DEBUG_COMM("Disable SPE retry counter successful"); } else { DEBUG_CRITICAL("Failed to disable SPE retry counter"); } } } break; case HPSMARTCARDKEYBOARD: case HP_CCIDSMARTCARDKEYBOARD: case FUJITSUSMARTKEYB: /* the Secure Pin Entry is bogus so disable it * https://web.archive.org/web/20120320001756/http://martinpaljak.net/2011/03/19/insecure-hp-usb-smart-card-keyboard/ * * The problem is that the PIN code entered using the Secure * Pin Entry function is also sent to the host. */ ccid_descriptor->bPINSupport = 0; break; case HID_AVIATOR: /* The chip advertises pinpad but actually doesn't have one */ ccid_descriptor->bPINSupport = 0; /* Firmware uses chaining */ ccid_descriptor->dwFeatures &= ~CCID_CLASS_EXCHANGE_MASK; ccid_descriptor->dwFeatures |= CCID_CLASS_EXTENDED_APDU; break; #if 0 /* SCM SCR331-DI contactless */ case SCR331DI: /* SCM SCR331-DI-NTTCOM contactless */ case SCR331DINTTCOM: /* SCM SDI010 contactless */ case SDI010: /* the contactless reader is in the second slot */ if (ccid_descriptor->bCurrentSlotIndex > 0) { unsigned char cmd1[] = { 0x00 }; /* command: 00 ?? * response: 06 10 03 03 00 00 00 01 FE FF FF FE 01 ?? */ unsigned char cmd2[] = { 0x02 }; /* command: 02 ?? * response: 00 ?? */ unsigned char res[20]; unsigned int length_res = sizeof(res); if ((IFD_SUCCESS == CmdEscape(reader_index, cmd1, sizeof(cmd1), res, &length_res, 0)) && (IFD_SUCCESS == CmdEscape(reader_index, cmd2, sizeof(cmd2), res, &length_res, 0))) { DEBUG_COMM("SCM SCR331-DI contactless detected"); } else { DEBUG_COMM("SCM SCR331-DI contactless init failed"); } /* hack since the contactless reader do not share dwFeatures */ ccid_descriptor->dwFeatures &= ~CCID_CLASS_EXCHANGE_MASK; ccid_descriptor->dwFeatures |= CCID_CLASS_SHORT_APDU; ccid_descriptor->dwFeatures |= CCID_CLASS_AUTO_IFSD; } break; #endif case CHERRY_KC1000SC: if ((0x0100 == ccid_descriptor->IFD_bcdDevice) && (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK) == CCID_CLASS_SHORT_APDU) { /* firmware 1.00 is bogus * With a T=1 card and case 2 APDU (data from card to * host) the maximum size returned by the reader is 128 * byes. The reader is then using chaining as with * extended APDU. */ ccid_descriptor->dwFeatures &= ~CCID_CLASS_EXCHANGE_MASK; ccid_descriptor->dwFeatures |= CCID_CLASS_EXTENDED_APDU; } break; case ElatecTWN4: case SCM_SCL011: /* restore default timeout (modified in ccid_open_hack_pre()) */ ccid_descriptor->readTimeout = DEFAULT_COM_READ_TIMEOUT; break; } /* Gemalto readers may report additional information */ if (GET_VENDOR(ccid_descriptor->readerID) == VENDOR_GEMALTO) set_gemalto_firmware_features(reader_index); return return_value; } /* ccid_open_hack_post */
/***************************************************************************** * * OpenSerialByName: open the port * *****************************************************************************/ status_t OpenSerialByName(unsigned int reader_index, char *dev_name) { struct termios current_termios; unsigned int reader = reader_index; /* 255 is MAX_DEVICENAME in pcscd.h */ char reader_name[255] = "GemPCTwin"; char *p; status_t ret; DEBUG_COMM3("Reader index: %X, Device: %s", reader_index, dev_name); /* parse dev_name using the pattern "device:name" */ p = strchr(dev_name, ':'); if (p) { /* copy the second part of the string */ strlcpy(reader_name, p+1, sizeof(reader_name)); /* replace ':' by '\0' so that dev_name only contains the device name */ *p = '\0'; } ret = set_ccid_descriptor(reader_index, reader_name, dev_name); if (STATUS_UNSUCCESSFUL == ret) return STATUS_UNSUCCESSFUL; /* secondary slot so do not physically open the device */ if (STATUS_SECONDARY_SLOT == ret) return STATUS_SUCCESS; serialDevice[reader].fd = open(dev_name, O_RDWR | O_NOCTTY); if (-1 == serialDevice[reader].fd) { DEBUG_CRITICAL3("open %s: %s", dev_name, strerror(errno)); return STATUS_UNSUCCESSFUL; } /* Set RTS signal to low to prevent the smart card reader * from sending its plug and play string. */ { int flags; if (ioctl(serialDevice[reader].fd, TIOCMGET, &flags) < 0) { DEBUG_CRITICAL2("Get RS232 signals state failed: %s", strerror(errno)); } else { flags &= ~TIOCM_RTS; if (ioctl(serialDevice[reader].fd, TIOCMSET, &flags) < 0) { DEBUG_CRITICAL2("Set RTS to low failed: %s", strerror(errno)); } else { DEBUG_COMM("Plug-n-Play inhibition successful"); } } } /* set channel used */ serialDevice[reader].device = strdup(dev_name); /* empty in and out serial buffers */ if (tcflush(serialDevice[reader].fd, TCIOFLUSH)) DEBUG_INFO2("tcflush() function error: %s", strerror(errno)); /* get config attributes */ if (tcgetattr(serialDevice[reader].fd, ¤t_termios) == -1) { DEBUG_INFO2("tcgetattr() function error: %s", strerror(errno)); (void)close(serialDevice[reader].fd); serialDevice[reader].fd = -1; return STATUS_UNSUCCESSFUL; } /* IGNBRK: ignore BREAK condition on input * IGNPAR: ignore framing errors and parity errors. */ current_termios.c_iflag = IGNBRK | IGNPAR; current_termios.c_oflag = 0; /* Raw output modes */ /* CS8: 8-bits character size * CSTOPB: set two stop bits * CREAD: enable receiver * CLOCAL: ignore modem control lines */ current_termios.c_cflag = CS8 | CSTOPB | CREAD | CLOCAL; /* Do not echo characters because if you connect to a host it or your modem * will echo characters for you. Don't generate signals. */ current_termios.c_lflag = 0; #ifndef ANDROID /* set serial port speed to 115200 bauds */ (void)cfsetspeed(¤t_termios, B115200); DEBUG_INFO("Set serial port baudrate to 115200 and correct configuration"); #endif if (tcsetattr(serialDevice[reader].fd, TCSANOW, ¤t_termios) == -1) { (void)close(serialDevice[reader].fd); serialDevice[reader].fd = -1; DEBUG_INFO2("tcsetattr error: %s", strerror(errno)); return STATUS_UNSUCCESSFUL; } /* perform a command to be sure a Gemalto reader is connected * get the reader firmware */ { unsigned char tx_buffer[] = { 0x02 }; unsigned char rx_buffer[50]; unsigned int rx_length = sizeof(rx_buffer); /* 2 seconds timeout to not wait too long if no reader is connected */ serialDevice[reader].ccid.readTimeout = 2*1000; if (IFD_SUCCESS != CmdEscape(reader_index, tx_buffer, sizeof(tx_buffer), rx_buffer, &rx_length)) { DEBUG_CRITICAL("Get firmware failed. Maybe the reader is not connected"); (void)CloseSerial(reader_index); return STATUS_UNSUCCESSFUL; } /* normal timeout: 2 seconds */ serialDevice[reader].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT ; rx_buffer[rx_length] = '\0'; DEBUG_INFO2("Firmware: %s", rx_buffer); } /* perform a command to configure GemPC Twin reader card movement * notification to synchronous mode: the card movement is notified _after_ * the host command and _before_ the reader anwser */ { unsigned char tx_buffer[] = { 0x01, 0x01, 0x01}; unsigned char rx_buffer[50]; unsigned int rx_length = sizeof(rx_buffer); if (IFD_SUCCESS != CmdEscape(reader_index, tx_buffer, sizeof(tx_buffer), rx_buffer, &rx_length)) { DEBUG_CRITICAL("Change card movement notification failed."); (void)CloseSerial(reader_index); return STATUS_UNSUCCESSFUL; } } serialDevice[reader_index].ccid.sIFD_serial_number = NULL; serialDevice[reader_index].ccid.sIFD_iManufacturer = NULL; serialDevice[reader_index].ccid.IFD_bcdDevice = 0; return STATUS_SUCCESS; } /* OpenSerialByName */