1/* 2 ccid.c: CCID common code 3 Copyright (C) 2003-2005 Ludovic Rousseau 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public License 16 along with this library; if not, write to the Free Software Foundation, 17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18*/ 19 20/* 21 * $Id: ccid.c 4346 2009-07-28 13:39:37Z rousseau $ 22 */ 23 24#include <stdio.h> 25#include <stdlib.h> 26#include <string.h> 27#include <pcsclite.h> 28#include <ifdhandler.h> 29 30#include "config.h" 31#include "debug.h" 32#include "ccid.h" 33#include "defs.h" 34#include "ccid_ifdhandler.h" 35#include "commands.h" 36#include "ccid_usb.h" 37 38/***************************************************************************** 39 * 40 * ccid_open_hack_pre 41 * 42 ****************************************************************************/ 43int ccid_open_hack_pre(unsigned int reader_index) 44{ 45 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); 46 int doInterruptRead = 1; 47 48 switch (ccid_descriptor->readerID) 49 { 50 case CARDMAN3121+1: 51 /* Reader announces APDU but is in fact TPDU */ 52 ccid_descriptor->dwFeatures &= ~CCID_CLASS_EXCHANGE_MASK; 53 ccid_descriptor->dwFeatures |= CCID_CLASS_TPDU; 54 break; 55 56 case MYSMARTPAD: 57 ccid_descriptor->dwMaxIFSD = 254; 58 break; 59 60 case CL1356D: 61 /* the firmware needs some time to initialize */ 62 (void)sleep(1); 63 ccid_descriptor->readTimeout = 60; /* 60 seconds */ 64 break; 65 66 case KOBIL_TRIBANK: 67 /* the InterruptRead does not timeout (on Mac OS X) */ 68 doInterruptRead = 0; 69 break; 70 } 71 72 /* CCID */ 73 if (doInterruptRead && (0 == ccid_descriptor->bInterfaceProtocol)) 74 { 75#ifndef TWIN_SERIAL 76 /* just wait for 10ms in case a notification is in the pipe */ 77 (void)InterruptRead(reader_index, 10); 78#endif 79 } 80 81 /* ICCD type A */ 82 if (ICCD_A == ccid_descriptor->bInterfaceProtocol) 83 { 84 unsigned char tmp[MAX_ATR_SIZE]; 85 unsigned int n = sizeof(tmp); 86 87 DEBUG_COMM("ICCD type A"); 88 (void)CmdPowerOff(reader_index); 89 (void)CmdPowerOn(reader_index, &n, tmp, CCID_CLASS_AUTO_VOLTAGE); 90 (void)CmdPowerOff(reader_index); 91 } 92 93 /* ICCD type B */ 94 if (ICCD_B == ccid_descriptor->bInterfaceProtocol) 95 { 96 unsigned char tmp[MAX_ATR_SIZE]; 97 unsigned int n = sizeof(tmp); 98 99 DEBUG_COMM("ICCD type B"); 100 if (CCID_CLASS_SHORT_APDU == 101 (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)) 102 { 103 /* use the extended APDU comm alogorithm */ 104 ccid_descriptor->dwFeatures &= ~CCID_CLASS_EXCHANGE_MASK; 105 ccid_descriptor->dwFeatures |= CCID_CLASS_EXTENDED_APDU; 106 } 107 108 (void)CmdPowerOff(reader_index); 109 (void)CmdPowerOn(reader_index, &n, tmp, CCID_CLASS_AUTO_VOLTAGE); 110 (void)CmdPowerOff(reader_index); 111 } 112 113 return 0; 114} /* ccid_open_hack_pre */ 115 116/***************************************************************************** 117 * 118 * ccid_open_hack_post 119 * 120 ****************************************************************************/ 121int ccid_open_hack_post(unsigned int reader_index) 122{ 123 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); 124 125 switch (ccid_descriptor->readerID) 126 { 127 case GEMPCKEY: 128 case GEMPCTWIN: 129 /* Reader announces TPDU but can do APDU */ 130 if (DriverOptions & DRIVER_OPTION_GEMPC_TWIN_KEY_APDU) 131 { 132 unsigned char cmd[] = { 0xA0, 0x02 }; 133 unsigned char res[10]; 134 unsigned int length_res = sizeof(res); 135 136 if (CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res) == IFD_SUCCESS) 137 { 138 ccid_descriptor->dwFeatures &= ~CCID_CLASS_EXCHANGE_MASK; 139 ccid_descriptor->dwFeatures |= CCID_CLASS_SHORT_APDU; 140 } 141 } 142 break; 143 144 case GEMPCPINPAD: 145 /* load the l10n strings in the pinpad memory */ 146 { 147#define L10N_HEADER_SIZE 5 148#define L10N_STRING_MAX_SIZE 16 149#define L10N_NB_STRING 10 150 151 unsigned char cmd[L10N_HEADER_SIZE + L10N_NB_STRING * L10N_STRING_MAX_SIZE]; 152 unsigned char res[20]; 153 unsigned int length_res = sizeof(res); 154 int offset, i, j; 155 156 const char *fr[] = { 157 "Entrer PIN", 158 "Nouveau PIN", 159 "Confirmer PIN", 160 "PIN correct", 161 "PIN Incorrect !", 162 "Delai depasse", 163 "* essai restant", 164 "Inserer carte", 165 "Erreur carte", 166 "PIN bloque" }; 167 168 const char *de[] = { 169 "PIN eingeben", 170 "Neue PIN", 171 "PIN bestatigen", 172 "PIN korrect", 173 "Falsche PIN !", 174 "Zeit abgelaufen", 175 "* Versuche ubrig", 176 "Karte einstecken", 177 "Fehler Karte", 178 "PIN blockiert" }; 179 180 const char *es[] = { 181 "Introducir PIN", 182 "Nuevo PIN", 183 "Confirmar PIN", 184 "PIN OK", 185 "PIN Incorrecto !", 186 "Tiempo Agotado", 187 "* ensayos quedan", 188 "Introducir Tarj.", 189 "Error en Tarjeta", 190 "PIN bloqueado" }; 191 192 const char *it[] = { 193 "Inserire PIN", 194 "Nuovo PIN", 195 "Confermare PIN", 196 "PIN Corretto", 197 "PIN Errato !", 198 "Tempo scaduto", 199 "* prove rimaste", 200 "Inserire Carta", 201 "Errore Carta", 202 "PIN ostruito"}; 203 204 const char *pt[] = { 205 "Insira PIN", 206 "Novo PIN", 207 "Conf. novo PIN", 208 "PIN OK", 209 "PIN falhou!", 210 "Tempo expirou", 211 "* tentiv. restam", 212 "Introduza cartao", 213 "Erro cartao", 214 "PIN bloqueado" }; 215 216 const char *nl[] = { 217 "Inbrengen code", 218 "Nieuwe code", 219 "Bevestig code", 220 "Code aanvaard", 221 "Foute code", 222 "Time out", 223 "* Nog Pogingen", 224 "Kaart inbrengen", 225 "Kaart fout", 226 "Kaart blok" }; 227 228 const char *tr[] = { 229 "PIN Giriniz", 230 "Yeni PIN", 231 "PIN Onayala", 232 "PIN OK", 233 "Yanlis PIN", 234 "Zaman Asimi", 235 "* deneme kaldi", 236 "Karti Takiniz", 237 "Kart Hatasi", 238 "Kart Kilitli" }; 239 240 const char *en[] = { 241 "Enter PIN", 242 "New PIN", 243 "Confirm PIN", 244 "PIN OK", 245 "Incorrect PIN!", 246 "Time Out", 247 "* retries left", 248 "Insert Card", 249 "Card Error", 250 "PIN blocked" }; 251 252 char *lang; 253 const char **l10n; 254 255 lang = getenv("LANG"); 256 if (NULL == lang) 257 l10n = en; 258 else 259 { 260 if (0 == strncmp(lang, "fr", 2)) 261 l10n = fr; 262 else if (0 == strncmp(lang, "de", 2)) 263 l10n = de; 264 else if (0 == strncmp(lang, "es", 2)) 265 l10n = es; 266 else if (0 == strncmp(lang, "it", 2)) 267 l10n = it; 268 else if (0 == strncmp(lang, "pt", 2)) 269 l10n = pt; 270 else if (0 == strncmp(lang, "nl", 2)) 271 l10n = nl; 272 else if (0 == strncmp(lang, "tr", 2)) 273 l10n = tr; 274 else 275 l10n = en; 276 } 277 278 offset = 0; 279 cmd[offset++] = 0xB2; /* load strings */ 280 cmd[offset++] = 0xA0; /* address of the memory */ 281 cmd[offset++] = 0x00; /* address of the first byte */ 282 cmd[offset++] = 0x4D; /* magic value */ 283 cmd[offset++] = 0x4C; /* magic value */ 284 285 /* for each string */ 286 for (i=0; i<L10N_NB_STRING; i++) 287 { 288 /* copy the string */ 289 for (j=0; l10n[i][j]; j++) 290 cmd[offset++] = l10n[i][j]; 291 292 /* pad with " " */ 293 for (; j<L10N_STRING_MAX_SIZE; j++) 294 cmd[offset++] = ' '; 295 } 296 297 (void)sleep(1); 298 if (IFD_SUCCESS == CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res)) 299 { 300 DEBUG_COMM("l10n string loaded successfully"); 301 } 302 else 303 { 304 DEBUG_COMM("Failed to load l10n strings"); 305 } 306 } 307 break; 308 309#if 0 310 /* SCM SCR331-DI contactless */ 311 case SCR331DI: 312 /* SCM SCR331-DI-NTTCOM contactless */ 313 case SCR331DINTTCOM: 314 /* SCM SDI010 contactless */ 315 case SDI010: 316 /* the contactless reader is in the second slot */ 317 if (ccid_descriptor->bCurrentSlotIndex > 0) 318 { 319 unsigned char cmd1[] = { 0x00 }; 320 /* command: 00 ?? 321 * response: 06 10 03 03 00 00 00 01 FE FF FF FE 01 ?? */ 322 unsigned char cmd2[] = { 0x02 }; 323 /* command: 02 ?? 324 * response: 00 ?? */ 325 326 unsigned char res[20]; 327 unsigned int length_res = sizeof(res); 328 329 if ((IFD_SUCCESS == CmdEscape(reader_index, cmd1, sizeof(cmd1), res, &length_res)) 330 && (IFD_SUCCESS == CmdEscape(reader_index, cmd2, sizeof(cmd2), res, &length_res))) 331 { 332 DEBUG_COMM("SCM SCR331-DI contactless detected"); 333 } 334 else 335 { 336 DEBUG_COMM("SCM SCR331-DI contactless init failed"); 337 } 338 339 /* hack since the contactless reader do not share dwFeatures */ 340 ccid_descriptor->dwFeatures &= ~CCID_CLASS_EXCHANGE_MASK; 341 ccid_descriptor->dwFeatures |= CCID_CLASS_SHORT_APDU; 342 343 ccid_descriptor->dwFeatures |= CCID_CLASS_AUTO_IFSD; 344 } 345 break; 346#endif 347 } 348 349 return 0; 350} /* ccid_open_hack_post */ 351 352/***************************************************************************** 353 * 354 * ccid_error 355 * 356 ****************************************************************************/ 357void ccid_error(int error, const char *file, int line, const char *function) 358{ 359 const char *text; 360 char var_text[30]; 361 362 switch (error) 363 { 364 case 0x00: 365 text = "Command not supported or not allowed"; 366 break; 367 368 case 0x01: 369 text = "Wrong command length"; 370 break; 371 372 case 0x05: 373 text = "Invalid slot number"; 374 break; 375 376 case 0xA2: 377 text = "Card short-circuiting. Card powered off"; 378 break; 379 380 case 0xA3: 381 text = "ATR too long (> 33)"; 382 break; 383 384 case 0xAB: 385 text = "No data exchanged"; 386 break; 387 388 case 0xB0: 389 text = "Reader in EMV mode and T=1 message too long"; 390 break; 391 392 case 0xBB: 393 text = "Protocol error in EMV mode"; 394 break; 395 396 case 0xBD: 397 text = "Card error during T=1 exchange"; 398 break; 399 400 case 0xBE: 401 text = "Wrong APDU command length"; 402 break; 403 404 case 0xE0: 405 text = "Slot busy"; 406 break; 407 408 case 0xEF: 409 text = "PIN cancelled"; 410 break; 411 412 case 0xF0: 413 text = "PIN timeout"; 414 break; 415 416 case 0xF2: 417 text = "Busy with autosequence"; 418 break; 419 420 case 0xF3: 421 text = "Deactivated protocol"; 422 break; 423 424 case 0xF4: 425 text = "Procedure byte conflict"; 426 break; 427 428 case 0xF5: 429 text = "Class not supported"; 430 break; 431 432 case 0xF6: 433 text = "Protocol not supported"; 434 break; 435 436 case 0xF7: 437 text = "Invalid ATR checksum byte (TCK)"; 438 break; 439 440 case 0xF8: 441 text = "Invalid ATR first byte"; 442 break; 443 444 case 0xFB: 445 text = "Hardware error"; 446 break; 447 448 case 0xFC: 449 text = "Overrun error"; 450 break; 451 452 case 0xFD: 453 text = "Parity error during exchange"; 454 break; 455 456 case 0xFE: 457 text = "Card absent or mute"; 458 break; 459 460 case 0xFF: 461 text = "Activity aborted by Host"; 462 break; 463 464 default: 465 if ((error >= 1) && (error <= 127)) 466 { 467 (void)snprintf(var_text, sizeof(var_text), "error on byte %d", 468 error); 469 text = var_text; 470 } 471 else 472 (void)snprintf(var_text, sizeof(var_text), 473 "Unknown CCID error: 0x%02X", error); 474 text = var_text; 475 break; 476 } 477 log_msg(PCSC_LOG_ERROR, "%s:%d:%s %s", file, line, function, text); 478 479} /* ccid_error */ 480 481