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