root/trunk/src/libopensc/card-belpic.c

Revision 3177, 49.6 kB (checked in by aj, 17 months ago)

fix compiler/sparse warnings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * card-belpic.c: Support for Belgium EID card
3 *
4 * Copyright (C) 2003, Zetes Belgium
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21/*     About the Belpic (Belgian Personal Identity Card) card
22 *
23 * The Belpic card is a Cyberflex Java card, so you normaly communicate
24 * with an applet running on the card. In order to support a pkcs15 file
25 * structure, an  applet (the Belpic applet) has been build that emulates
26 * this. So the card's behaviour is specific for this Belpic applet, that's
27 * why a separate driver has been made.
28 *
29 * The card contains the citizen's ID data (name, address, photo, ...) and
30 * her keys and certs. The ID data are in a seperate directory on the card and
31 * are not handled by this software. For the cryptographic data (keys and certs)
32 * a pkcs#15 structure has been chosen and they can be accessed and used
33 * by the OpenSC software.
34 *
35 * The current situation about the cryptographic data is: there is 1 PIN
36 * that protects 2 private keys and corresponding certs. Then there is a
37 * CA cert and the root cert. The first key (Auth Key) can be used for
38 * authentication, the second one (NonRep Key) for non repudation purposes
39 * (so it can be used as an alternative to manual signatures).
40 *
41 * There are some special things to note, which all have some consequences:
42 * (1) the SELECT FILE command doesn't return any FCI (file length, type, ...)
43 * (2) the NonRep key needs a VERIFY PIN before a signature can be done with it
44 * (3) pin pad readers had to be supported by a proprietory interface (as at
45 *     that moment no other solution was known/avaiable/ready)
46 * The consequences are:
47 *
48 * For (1): we let the SELECT FILE command return that the file length is
49 * a fixed large number and that each file is a transparant working EF
50 * (except the root dir 3F 00). This way however, there is a problem with the
51 * sc_read_binary() function that will only stop reading untill it receivces
52 * a 0. Therefore, we use the 'next_idx' trick. Or, if that might fail
53 * and so a READ BINARY past the end of file is done, length 0 is returned
54 * instead of an error code.
55 *
56 * For (2), we decided that a GUI for asking the PIN would be the best
57 * thing to do (another option would be to make 2 virtual slots but that
58 * causes other problems and is less user-friendly). A GUI being popped up
59 * by the pkcs11 lib before each NonRep signature has another important
60 * security advantage: applications that cache the PIN can't silently do
61 * a NonRep signature because there will allways be the GUI.
62 *
63 * For (3), we link dynamically against a pin pad lib (DLL) that implements the
64 * proprietory API for a specific pin pad. For each pin pad reader (identified
65 * by it's PC/SC reader name), a pin pad lib correspondends. Some reader/lib
66 * name pairs are hardcoded, and others can be added in the config file.
67 * Note that there's also a GUI used in this case: if a signature with the
68 * NonRep key is done: a dialog box is shown that asks the user to enter
69 * her PIN on the pin pad reader in order to make a legally valid signature.
70 *
71 * Further the (current) Belpic card as quite some limitations:
72 * no key pair generation or update of data except after establishing a Secure
73 * Channel or CTV-authentication (which can only be done at the municipalities),
74 * no encryption. The result is that only a very limited amount of functions
75 * is/had to be implemented to get the pkcs11 library working.
76 *
77 * About the belpic_set_language: the RA-PC software (including the pkcs11 lib)
78 * in the Brussels' communities should be able to change the language of the GUI
79 * messages. So the language set by this function takes priority on all other
80 * language-selection  functionality.
81 */
82
83#include "internal.h"
84#include "log.h"
85#include <stdlib.h>
86#include <string.h>
87
88#ifdef BELPIC_PIN_PAD
89#ifndef HAVE_GUI
90#define HAVE_GUI
91#endif
92#endif
93
94#ifdef BELPIC_PIN_PAD
95#include "winscard.h"
96#include "scr.h"
97#endif
98
99/* These defines are disabled for OpenSC */
100#if 0
101#define BELPIC_SET_LANG
102#define GET_LANG_FROM_CARD
103#define HAVE_ALLOW_SSO
104#endif
105
106#ifdef HAVE_GUI
107#include "scgui.h"
108#ifndef SCR_USAGE_SIGN
109#define SCR_USAGE_SIGN 2        /* in scr.h */
110#endif
111#ifndef SCR_USAGE_AUTH
112#define SCR_USAGE_AUTH 1
113#endif
114#endif
115
116/* To be removed */
117#include <time.h>
118static long t1, t2, tot_read = 0, tot_dur = 0, dur;
119
120#define BELPIC_VERSION                  "1.4"
121
122/* Most of the #defines here are also present in the pkcs15 files, but
123 * because this driver has no access to them, it's hardcoded here. If
124 * other Belpic cards with other 'settings' appear, we'll have to move
125 * these #defines to the struct belpic_priv_data */
126#define BELPIC_MAX_FILE_SIZE            65535
127#define BELPIC_PIN_BUF_SIZE             8
128#define BELPIC_MIN_USER_PIN_LEN         4
129#define BELPIC_MAX_USER_PIN_LEN         12
130#define BELPIC_PIN_ENCODING             SC_PIN_ENCODING_GLP
131#define BELPIC_PAD_CHAR                 0xFF
132#define BELPIC_KEY_REF_NONREP           0x83
133
134/* Used for a trick in select file and read binary */
135static size_t next_idx = (size_t)-1;
136
137static struct sc_atr_table belpic_atrs[] = {
138        /* Applet V1.1 */
139        { "3B:98:13:40:0A:A5:03:01:01:01:AD:13:11", NULL, NULL, SC_CARD_TYPE_BELPIC_EID, 0, NULL },
140        /* Applet V1.0 with new EMV-compatible ATR */
141        { "3B:98:94:40:0A:A5:03:01:01:01:AD:13:10", NULL, NULL, SC_CARD_TYPE_BELPIC_EID, 0, NULL },
142        /* Applet beta 5 + V1.0 */
143        { "3B:98:94:40:FF:A5:03:01:01:01:AD:13:10", NULL, NULL, SC_CARD_TYPE_BELPIC_EID, 0, NULL },
144#if 0
145        /* Applet beta 3 + 4 */
146        { "3B:98:11:40:FF:A5:03:01:01:01:AD:13:04", NULL, NULL, SC_CARD_TYPE_BELPIC_EID, 0, NULL },
147        /* Applet beta 2 */
148        { "3B:68:00:00:29:05:01:02:01:AD:13:03", NULL, NULL, SC_CARD_TYPE_BELPIC_EID, 0, NULL },
149#endif
150        { NULL, NULL, NULL, 0, 0, NULL }
151};
152
153struct belpic_priv_data {
154        int lang;
155        int options;
156#ifdef BELPIC_PIN_PAD
157        FARPROC scr_init;
158        FARPROC scr_verify_pin;
159        FARPROC scr_change_pin;
160        char szPinPadDll[64];
161#endif
162};
163
164#define DRVDATA(card)   ((struct belpic_priv_data *) ((card)->drv_data))
165
166/* Single Sign On */
167#ifdef HAVE_ALLOW_SSO
168#define SSO_OK(drv) ((drv)->allow_sso)
169#else
170#define SSO_OK(drv) 0
171#endif
172
173static struct sc_card_operations belpic_ops;
174static struct sc_card_driver belpic_drv = {
175        "Belpic cards",
176        "belpic",
177        &belpic_ops,
178        NULL, 0, NULL
179};
180static const struct sc_card_operations *iso_ops = NULL;
181
182#define LNG_ENG                 0
183#define LNG_DUTCH               1
184#define LNG_FRENCH              2
185#define LNG_GERMAN              3
186#define LNG_NONE                0xFFFF
187
188#ifdef BELPIC_PIN_PAD
189
190/* Option flags from the config file */
191#define PP_MSG_AUTH_PIN                 0x00000001
192#define PP_MSG_WRONG_PIN                0x00000002
193#define PP_MSG_CHANGEPIN_MISMATCH       0x00000004
194#define PP_MSG_PIN_BLOCKED              0x00000008
195
196/* Hardcoded pin pad reader names (PC/SC) and their pin pad lib */
197static char *pp_reader_names[] = {
198        "Xiring X Pass Serial",
199        NULL
200};
201static char *pp_reader_libs[] = {
202        "xireid",
203        NULL
204};
205
206static BYTE aid_belpic[] = { 0xA0, 0x00, 0x00, 0x01, 0x77, 0x50, 0x4B, 0x43, 0x53, 0x2D, 0x31, 0x35 };
207static SCR_Application scr_app_belpic = {
208        {aid_belpic, sizeof(aid_belpic)},
209        "ID",
210        NULL
211};
212static char *app_id_longstr[] = {
213        "Identity",
214        "Identiteit",
215        "Identité",
216        "Identität"
217};
218#endif  /* BELPIC_PIN_PAD */
219
220#if defined(HAVE_GUI) ||defined(BELPIC_PIN_PAD)
221static char *pin_usg_sig[] = {
222        "Signature",
223        "Handtekening",
224        "Signature",
225        "Signatur"
226};
227static char *pin_usg_auth[] = {
228        "Authentication",
229        "Authentificatie",
230        "Authentification",
231        "Authentifizierung"
232};
233#endif  /* defined(HAVE_GUI) ||defined(BELPIC_PIN_PAD) */
234
235#ifdef BELPIC_PIN_PAD
236static char *lang_codes[4] = {
237        "en",
238        "nl",
239        "fr",
240        "de"
241};
242static char *pp_msg_auth_sh[] = {
243        "Authentication",
244        "Authentificatie",
245        "Authentification",
246        "Kennzeichnung"
247};
248static char *pp_msg_auth[] = {
249        "Enter your PIN on the reader, in order to authenticate yourself",
250        "Geef uw PIN in op de lezer, om u te authentificeren",
251        "Entrez votre PIN sur le lecteur, pour vous authentifier",
252        "Bitte geben Sie Ihre PIN am Kartenlesegerät ein, um sich zu authentifizieren"
253};
254static char *pp_msg_sign_sh[] = {
255        "Signature",
256        "Handtekening",
257        "Signature",
258        "Signatur"
259};
260static char *pp_msg_sign[] = {
261        "Caution: You are about to make a legally binding electronic signature with your identity card.\nPlease enter your PIN on the card reader to continue or click the Cancel button.\n\nIf you only want to log on to a web site or server, do NOT enter your PIN and click the Cancel button.",
262        "Let op: u gaat een wettelijk bindende electronische handtekening plaatsen met uw identiteitskaart.\nGeef uw PIN in op de kaartlezer om verder te gaan of klik op Stoppen.\n\nAls u enkel wil aanloggen op een web site of een server, geef uw PIN NIET in en klik op Stoppen.",
263        "Attention: vous allez apposer une signature électronique juridiquement valide avec votre carte d'identité.\nVeuillez entrer votre PIN sur le lecteur externe pour continuer ou cliquez sur Annuler.\n\nSi vous désirez seulement vous connecter à un site ou un serveur, n'entrez PAS votre PIN et cliquez sur Annuler.",
264        "Achtung: Mit Ihrem Personalausweis werden Sie eine rechtlich bindende elektronische Signatur setzen.\nBitte geben Sie Ihre PIN am Kartenlesgerät ein zum weitergehen oder klicken Sie auf Abbrechen.\n\nWenn Sie nur auf das Internet gehen möchten, geben Sie bitte Ihre PIN NICHT ein, sondern klicken Sie auf Abbrechen."
265};
266static char *pp_msg_change_sh[] = {
267        "PIN change",
268        "PIN verandering",
269        "Modification du PIN ",
270        "PIN ändern"
271};
272static char *pp_msg_change[] = {
273        "Change your PIN on the reader",
274        "Verander uw PIN op de lezer",
275        "Modifiez votre PIN sur le lecteur",
276        "Bitte ändern Sie Ihre PIN am Kartenlesegerät"
277};
278static char *pp_msg_pin_mismatch[] = {
279        "The new PINs you entered were different.\n\nRetry or cancel?",
280        "De ingevoerde nieuwe PINs zijn verschillend.\n\nOpnieuw proberen of stoppen?",
281        "Les nouveaux PIN entrés sont différents.\n\nRéessayer ou annuler?",
282        "Die von Ihnen eingegebenen PINs unterscheiden sich.\n\nErneut versuchen oder abbrechen?"
283};
284
285struct pcsc_slot_data {
286        SCARDHANDLE pcsc_card;
287};                              /* comes from reader-pcsc.c */
288#define GET_SLOT_DATA(r) ((struct pcsc_slot_data *) (r)->drv_data)
289#define PCSC_ERROR(ctx, desc, rv) sc_error(ctx, desc ": %lx\n", rv);
290
291#endif  /* BELPIC_PIN_PAD */
292
293#ifdef BELPIC_SET_LANG
294
295#define MAX_READER_LEN  100
296typedef struct t_lang_info {
297        char reader[MAX_READER_LEN];
298        int lang;
299} t_lang_info;
300
301static t_lang_info lang_infos[SC_MAX_READERS];
302
303#endif  /* BELPIC_SET_LANG */
304
305/* Language support for the GUI messages */
306#ifdef HAVE_GUI
307
308#ifdef WIN32
309#define BTN_KEYB_SHORTCUT "&"
310#else
311#define BTN_KEYB_SHORTCUT "_"
312#endif
313
314static char *app_msg[] = {
315        "Identity",
316        "Identiteit",
317#ifdef _WIN32
318        "Identité",
319#else
320        "Identite",
321#endif
322#ifdef _WIN32
323        "Identität"
324#else
325        "Identitat",
326#endif
327};
328static char *btn_msg_retry[4] = {
329        BTN_KEYB_SHORTCUT"Try again",
330        BTN_KEYB_SHORTCUT"Opnieuw proberen",
331        BTN_KEYB_SHORTCUT"Réessayer",
332        BTN_KEYB_SHORTCUT"Erneut versuchen"
333};
334static char *btn_msg_cancel[4] = {
335        BTN_KEYB_SHORTCUT"Cancel",
336        BTN_KEYB_SHORTCUT"Stoppen",
337        BTN_KEYB_SHORTCUT"Annuler",
338        BTN_KEYB_SHORTCUT"Abbrechen"
339};
340static char *btn_msg_ok[4] = {
341        BTN_KEYB_SHORTCUT"OK",
342        BTN_KEYB_SHORTCUT"OK",
343        BTN_KEYB_SHORTCUT"OK",
344        BTN_KEYB_SHORTCUT"OK"
345};
346static char *btn_msg_close[4] = {
347        BTN_KEYB_SHORTCUT"Close",
348        BTN_KEYB_SHORTCUT"Sluiten",
349        BTN_KEYB_SHORTCUT"Fermer",
350        BTN_KEYB_SHORTCUT"Schliessen"
351};
352static char *enter_pin_msg_auth[] = {
353        "Enter your PIN, in order to authenticate yourself",
354        "Geef uw PIN in, om u te authentificeren",
355        "Entrez votre PIN, pour vous authentifier",
356        "Bitte geben Sie Ihre PIN ein, um sich zu authentifizieren"
357};
358static char *enter_pin_msg_sign[4] = {
359#ifdef _WIN32
360        "Caution: You are about to make a legally binding electronic signature with your identity card.\nPlease enter your PIN to continue or click the Cancel button.\n\nWarning: if you only want to log on to a web site or server, do NOT enter your PIN and click the Cancel button.",
361        "Let op: u gaat een wettelijk bindende electronische handtekening plaatsen met uw identiteitskaart.\nGeef uw PIN in om verder te gaan of klik op Stoppen.\n\nWaarschuwing: als u enkel wil aanloggen op een web site of een server, geef uw PIN NIET in en klik op Stoppen.",
362        "Attention: vous allez apposer une signature électronique juridiquement valide avec votre carte d'identité.\nVeuillez entrer votre PIN pour continuer ou cliquez sur Annuler.\n\nPrécaution: si vous désirez seulement vous connecter à un site ou un serveur, n'entrez PAS votre PIN et cliquez sur Annuler.",
363        "Achtung: Mit Ihrem Personalausweis werden Sie eine rechtlich bindende elektronische Signatur setzen.\nBitte geben Sie Ihre PIN ein zum weitergehen oder klicken Sie auf Abbrechen.\n\nWarnung: Wenn Sie nur auf das Internet gehen möchten, geben Sie bitte Ihre PIN NICHT ein, sondern klicken Sie auf Abbrechen."
364#else
365#ifdef __APPLE__
366        "CAUTION: you are about to make a legally binding electronic signature with your identity card. Please enter your PIN to continue or press the Cancel button.                                        If you only want to log on to a web site or a server, do NOT enter your PIN and press the Cancel button.",
367        "LET OP: u gaat een wettelijk bindende electronische handtekening plaatsen met uw identiteitskaart. Geef uw PIN in om verder te gaan of klik op Stoppen.                                    Als u enkel wil aanloggen op een web site of een server, geef uw PIN NIET in en klik op Stoppen.",
368        "ATTENTION: vous allez apposer une signature electronique\njuridiquement valide avec votre carte d'identite.Veuillez entrer votre PIN pour continuer ou cliquez sur Annuler. Si vous desirez seulement vous connecter a un site ou un serveur, n' entrez PAS votre PIN et cliquez sur Annuler.",
369        "ACHTUNG: Mit Ihrem Personalausweis werden Sie eine rechtlich bindende elektronische Signatur setzen. Geben Sie Ihre PIN ein zum weitergehen oder klicken Sie auf Abbrechen. Warnung: Wenn Sie nur auf das Internet gehen mochten, geben Sie bitte Ihre PIN NICHT ein, sondern klicken Sie auf Abbrechen."
370#else
371        "<u>Caution</u>: you are about to make a legally binding electronic\nsignature with your identity card.\nPlease enter your PIN to continue or press the Cancel button.\n\nIf you only want to log on to a web site or a server,\ndo <b>NOT</b> enter your PIN and press the Cancel button.",
372        "<u>Let op</u>: u gaat een wettelijk bindende electronische handtekening\nplaatsen met uw identiteitskaart.\nGeef uw PIN in om verder te gaan of klik op Stoppen.\n\nAls u enkel wil aanloggen op een web site\nof een server, geef uw PIN <b>NIET</b> in en klik op Stoppen.",
373        "<u>Attention</u>: vous allez apposer une signature electronique\njuridiquement valide avec votre carte d'identite.\nVeuillez entrer votre PIN pour continuer ou cliquez sur Annuler.\n\nSi vous desirez seulement vous connecter a un site\nou un serveur, n'entrez <b>PAS</b> votre PIN et cliquez sur Annuler.",
374        "<u>Achtung</u>: Mit Ihrem Personalausweis werden Sie eine rechtlich\r\nbindende elektronische Signatur setzen.\r\nGeben Sie Ihre PIN ein zum weitergehen oder klicken Sie auf Abbrechen.\r\n\r\nWarnung: Wenn Sie nur auf das Internet gehen mochten, geben\r\nSie bitte Ihre PIN <b>NICHT</b> ein, sondern klicken Sie auf Abbrechen."
375#endif
376#endif
377};
378static char *wrong_pin_len_msgs[4] = {
379        "Wrong PIN length",
380        "Foute PIN lengte",
381        "Longueur de PIN erroné",
382        "Falsche PIN-Länge"
383};
384static char *wrong_pin_msgs[4] = {
385        "Wrong PIN, %d tries left\n\nRetry or cancel?",
386        "Foute PIN, nog %d pogingen\n\nOpnieuw proberen of stoppen?",
387        "PIN erroné, %d essais restants\n\nRéessayer ou annuler?",
388        "Falsche PIN, %d verbleibende Versuche\n\nErneut versuchen oder abbrechen?"
389};
390static char *pin_blocked_msgs[4] = {
391        "PIN blocked",
392        "PIN geblokkeerd",
393        "PIN bloqué ",
394        "PIN gesperrt"
395};
396
397#endif  /* HAVE_GUI */
398
399/* To be removed */
400#if 0
401static void dumphex(char *msg, const u8 * buf, int len)
402{
403        int i;
404        printf("%s", msg);
405        for (i = 0; i < len; i++)
406                printf("%02X ", buf[i]);
407        printf(" (%d bytes)\n", len);
408}
409#endif
410
411#ifdef BELPIC_PIN_PAD
412
413#define SCR_INIT_ID     100
414#define SCR_VERIFY_ID   101
415#define SCR_CHANGE_ID   102
416#define SCR_CARD_HANDLE 999
417
418struct tTLV {
419        unsigned char *base;
420        unsigned char *end;
421        unsigned char *current;
422        unsigned char *next;
423};
424
425static void TLVInit(struct tTLV *tlv, u8 * base, size_t size)
426{
427        tlv->base = base;
428        tlv->end = base + size;
429        tlv->current = tlv->next = base;
430}
431
432static void TLVNext(struct tTLV *tlv, u8 tag)
433{
434        assert(tlv->next + 2 < tlv->end);
435        tlv->current = tlv->next;
436        *(tlv->next++) = tag;
437        *(tlv->next++) = 0;
438}
439
440static void TLVAdd(struct tTLV *tlv, u8 val)
441{
442        assert(tlv->next + 1 < tlv->end);
443        *(tlv->next++) = val;
444        tlv->current[1]++;
445}
446
447static void TLVAddBuffer(struct tTLV *tlv, u8 * val, size_t size)
448{
449        assert(tlv->next + size < tlv->end);
450        memcpy(tlv->next, val, size);
451        tlv->current[1] = size;
452        tlv->next = tlv->next + size;
453}
454
455static size_t TLVLen(struct tTLV *tlv)
456{
457        return tlv->next - tlv->base;
458}
459
460static LONG SCR_SCardInit(LPCTSTR szPinPadDll, LPCTSTR szReader, DWORD version,
461                          SCR_SupportConstants * supported)
462{
463        LONG rv;
464        unsigned char sendbuf[256];
465        unsigned char recvbuf[2];
466        char szTemp[32];
467        DWORD dwRecvLength;
468        struct tTLV tlv;
469
470        memset(szTemp, 0, sizeof(szTemp));
471        memset(sendbuf, 0, sizeof(sendbuf));
472        memset(recvbuf, 0, sizeof(recvbuf));
473        dwRecvLength = sizeof(recvbuf);
474
475        /* Make TLV buffer */
476        TLVInit(&tlv, sendbuf, sizeof(sendbuf));
477        TLVNext(&tlv, 0x01);    /* Function ID */
478        sprintf(szTemp, "%ld", SCR_INIT_ID);
479        TLVAddBuffer(&tlv, (u8 *) szTemp, strlen(szTemp));
480        TLVNext(&tlv, 0x02);    /* PinPad Dll */
481        TLVAddBuffer(&tlv, (u8 *) szPinPadDll, strlen(szPinPadDll));
482        TLVNext(&tlv, 0x03);    /* Reader Name */
483        TLVAddBuffer(&tlv, (u8 *) szReader, strlen(szReader));
484        TLVNext(&tlv, 0x04);    /* Version */
485        sprintf(szTemp, "%ld", version);
486        TLVAddBuffer(&tlv, (u8 *) szTemp, strlen(szTemp));
487
488#ifdef HAVE_PCSC_OLD
489        rv = SCardControl(SCR_CARD_HANDLE, sendbuf, TLVLen(&tlv), recvbuf, &dwRecvLength);
490#else
491        rv = SCardControl(SCR_CARD_HANDLE, 0, sendbuf, TLVLen(&tlv),
492                          recvbuf, dwRecvLength, &dwRecvLength);
493#endif
494        if (dwRecvLength > 0) {
495                *supported = recvbuf[0];
496        } else {
497                rv = SC_ERROR_UNKNOWN_DATA_RECEIVED;
498        }
499
500        return rv;
501}
502
503static LONG SCR_SCardPIN(long lAction, LPCTSTR szPinPadDll, const SCR_Card * pCard, BYTE pinID,
504                         const SCR_PinUsage * pUsage, const SCR_Application * pApp,
505                         BYTE * pCardStatus)
506{
507        LONG rv;
508        unsigned char sendbuf[256];
509        unsigned char recvbuf[2];
510        char szTemp[32];
511        DWORD dwRecvLength;
512        struct tTLV tlv;
513
514        memset(szTemp, 0, sizeof(szTemp));
515        memset(recvbuf, 0, sizeof(recvbuf));
516        dwRecvLength = sizeof(recvbuf);
517
518        /* Make TLV buffer */
519        TLVInit(&tlv, sendbuf, sizeof(sendbuf));
520        TLVNext(&tlv, 0x01);    /* Function ID */
521        sprintf(szTemp, "%ld", lAction);
522        TLVAddBuffer(&tlv, (u8 *) szTemp, strlen(szTemp));
523        TLVNext(&tlv, 0x02);    /* PinPad Dll */
524        TLVAddBuffer(&tlv, (u8 *) szPinPadDll, strlen(szPinPadDll));
525        TLVNext(&tlv, 0x03);    /* SCR_Card Handle */
526        sprintf(szTemp, "%ld", pCard->hCard);
527        TLVAddBuffer(&tlv, (u8 *) szTemp, strlen(szTemp));
528        if (pCard->language != NULL) {
529                TLVNext(&tlv, 0x04);    /* SCR_Card language */
530                TLVAddBuffer(&tlv, (u8 *) pCard->language, strlen(pCard->language));
531        }
532        if (pCard->id.data != NULL) {
533                TLVNext(&tlv, 0x05);    /* SCR_Card id */
534                TLVAddBuffer(&tlv, pCard->id.data, pCard->id.length);
535        }
536        TLVNext(&tlv, 0x06);    /* PinID */
537        TLVAdd(&tlv, pinID);
538        if (pUsage != NULL) {
539                TLVNext(&tlv, 0x07);    /* SCR_PinUsage code */
540                sprintf(szTemp, "%ld", pUsage->code);
541                TLVAddBuffer(&tlv, (u8 *) szTemp, strlen(szTemp));
542                if (pUsage->shortString != NULL) {
543                        TLVNext(&tlv, 0x08);    /* SCR_PinUsage shortstring */
544                        TLVAddBuffer(&tlv, (u8 *) pUsage->shortString, strlen(pUsage->shortString));
545                }
546                if (pUsage->longString != NULL) {
547                        TLVNext(&tlv, 0x09);    /* SCR_PinUsage longstring */
548                        TLVAddBuffer(&tlv, (u8 *) pUsage->longString, strlen(pUsage->longString));
549                }
550        }
551        if (pApp->id.data != NULL) {
552                TLVNext(&tlv, 0x0A);    /* SCR_Application id */
553                TLVAddBuffer(&tlv, (u8 *) pApp->id.data, pApp->id.length);
554        }
555        if (pApp->shortString != NULL) {
556                TLVNext(&tlv, 0x0B);    /* SCR_Application shortstring */
557                TLVAddBuffer(&tlv, (u8 *) pApp->shortString, strlen(pApp->shortString));
558        }
559        if (pApp->longString != NULL) {
560                TLVNext(&tlv, 0x0C);    /* SCR_Application longstring */
561                TLVAddBuffer(&tlv, (u8 *) pApp->longString, strlen(pApp->longString));
562        }
563#ifdef HAVE_PCSC_OLD
564        rv = SCardControl(SCR_CARD_HANDLE, sendbuf, TLVLen(&tlv), recvbuf, &dwRecvLength);
565#else
566        rv = SCardControl(SCR_CARD_HANDLE, 0, sendbuf, TLVLen(&tlv),
567                          recvbuf, dwRecvLength, &dwRecvLength);
568#endif
569        if (dwRecvLength < 2) {
570                rv = SC_ERROR_UNKNOWN_DATA_RECEIVED;
571        } else {
572                memcpy(pCardStatus, recvbuf, 2);
573        }
574
575        return rv;
576}
577
578static LONG SCR_SCardVerifyPIN(LPCTSTR szPinPadDll, const SCR_Card * pCard, BYTE pinID,
579                               const SCR_PinUsage * pUsage, const SCR_Application * pApp,
580                               BYTE * pCardStatus)
581{
582        return SCR_SCardPIN(SCR_VERIFY_ID, szPinPadDll, pCard, pinID, pUsage, pApp, pCardStatus);
583}
584
585static LONG SCR_SCardChangePIN(LPCTSTR szPinPadDll, const SCR_Card * pCard, BYTE pinID,
586                               const SCR_Application * pApp, BYTE * pCardStatus)
587{
588        return SCR_SCardPIN(SCR_CHANGE_ID, szPinPadDll, pCard, pinID, NULL, pApp, pCardStatus);
589}
590
591#endif  /* BELPIC_PIN_PAD */
592
593#if defined(HAVE_GUI) ||defined(BELPIC_PIN_PAD)
594
595static int belpic_calculate_lang(sc_card_t *card)
596{
597        struct belpic_priv_data *priv = DRVDATA(card);
598        int lang = priv->lang;
599#ifdef BELPIC_SET_LANG
600        int i;
601
602        for (i = 0; i < SC_MAX_READERS; i++) {
603                if (lang_infos[i].reader[0] == '\0') {
604                        if (lang_infos[i].lang != LNG_NONE)
605                                lang = lang_infos[i].lang;
606                        break;
607                }
608                if (strncmp(lang_infos[i].reader, card->reader->name, MAX_READER_LEN) == 0) {
609                        if (lang_infos[i].lang != LNG_NONE)
610                                lang = lang_infos[i].lang;
611                }
612        }
613#endif  /* BELPIC_SET_LANG */
614
615        return lang;
616}
617
618#endif  /* defined(HAVE_GUI) ||defined(BELPIC_PIN_PAD) */
619
620#ifdef BELPIC_SET_LANG
621
622/**
623 * Force the language for the GUI and pinpad readers for one specific
624 * or for all readers.
625 * - IN reader: the PC/SC name of the reader, or NULL for all readers
626 * - IN lang: 0 for English, 1 for Dutch, 2 for French, 3 for German
627 *            and 0xFFFF to clear a previously selected language.
628 * Returns:
629 *    0 if OK,
630 *   -1 if a bad language code was given,
631 *   -2 if you called this function with more then MAX_READER_LEN (16)
632 *        different reader names and a lang code different from 0xFF
633 */
634int belpic_set_language(const char *reader, int lang)
635{
636        int i;
637
638        /* Check if language has a correct value */
639        if ((lang != LNG_NONE) && (lang < LNG_ENG || lang > LNG_GERMAN))
640                return -1;      /* Bad language */
641
642        /* Set or clear the language for the/all reader(s) */
643        for (i = 0; i < SC_MAX_READERS; i++) {
644                if (reader == NULL) {   /* For all readers */
645                        lang_infos[i].lang = lang;
646                        if (lang == LNG_NONE)
647                                lang_infos[i].reader[0] = '\0';
648                } else {        /* For only 1 reader */
649                        if (lang_infos[i].reader[0] == '\0') {  /* reader not yet present */
650                                strlcpy(lang_infos[i].reader, reader, sizeof(lang_infos[i].reader));
651                                lang_infos[i].lang = lang;
652                                break;
653                        } else if (strncmp(reader, lang_infos[i].reader, MAX_READER_LEN - 1) == 0) {
654                                lang_infos[i].lang = lang;
655                                break;
656                        } else if (i == SC_MAX_READERS - 1)
657                                return -2;      /* Too many readers (shouldn't happen) */
658                }
659        }
660
661        return 0;
662}
663
664#endif  /* BELPIC_SET_LANG */
665
666static int str2lang(sc_context_t *ctx, char *lang)
667{
668        if (memcmp(lang, "en", 2) == 0)
669                return LNG_ENG;
670        else if (memcmp(lang, "nl", 2) == 0)
671                return LNG_DUTCH;
672        else if (memcmp(lang, "fr", 2) == 0)
673                return LNG_FRENCH;
674        else if (memcmp(lang, "de", 2) == 0)
675                return LNG_GERMAN;
676        sc_debug(ctx, "Unknown/unsupported language code: %c%c\n", lang[0], lang[1]);
677        return -1;
678}
679
680#ifdef GET_LANG_FROM_CARD
681
682/* str is in lower case, the case of buf can be both, and buf is large enough */
683static int match_string(const char *str, const char *buf)
684{
685        int i = 0;
686
687        while (str[i] != '\0') {
688                if (str[i] != ((buf[i] >= 'A' && buf[i] <= 'Z') ? buf[i] + 32 : buf[i]))
689                        return 0;
690                i++;
691        }
692        return 1;               /* match */
693}
694
695static int get_pref(const char *prefs, int prefs_len, const char *title, const char *key, int *len)
696{
697        int i = 0;
698        int title_len = strlen(title);
699        int key_len = strlen(key);
700
701        while (prefs[i] != '\0' && i < prefs_len)
702                i++;
703        prefs_len = i;
704
705        i = 0;
706        while (i < prefs_len) {
707                while (i < prefs_len && prefs[i] != '[')
708                        i++;
709                if (i + title_len >= prefs_len)
710                        return -1;
711                if (!match_string(title, prefs + i)) {
712                        i++;
713                        continue;
714                }
715                i += title_len;
716                while (i < prefs_len) {
717                        while (i < prefs_len && (prefs[i] == '\r' || prefs[i] == '\n'))
718                                i++;
719                        if (i < prefs_len && prefs[i] == '[')
720                                break;
721                        if (i + key_len + 1 >= prefs_len)
722                                return -2;
723                        if (!match_string(key, prefs + i)) {
724                                i++;
725                                continue;
726                        }
727                        i += key_len;
728                        if (prefs[i] != '=')
729                                return -3;
730                        *len = ++i;
731                        while (*len < prefs_len && prefs[*len] != '\r' && prefs[*len] != '\n')
732                                (*len)++;
733                        *len -= i;
734                        return i;
735                }
736        }
737
738        return -1;
739}
740
741static int get_language(sc_card_t *card)
742{
743        sc_apdu_t apdu;
744        u8 prefs[240], *lg_value;
745        u8 path[] = { 0x3F, 0x00, 0xDF, 0x01, 0x40, 0x39 };
746        int r, i, len;
747
748        /* Get the language from the card's preferences file */
749        assert(card != NULL);
750
751        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x08, 0x0C);
752        apdu.lc = sizeof(path);
753        apdu.data = path;
754        apdu.datalen = sizeof(path);
755        apdu.resplen = 0;
756        apdu.le = 0;
757
758        r = sc_lock(card);
759        if (r < 0)
760                goto prefs_error;
761
762        r = sc_transmit_apdu(card, &apdu);
763        if (r < 0) {
764                sc_debug(card->ctx, "Select_File[prefs_file] command failed: %d\n", r);
765                sc_unlock(card);
766                goto prefs_error;
767        }
768        r = sc_check_sw(card, apdu.sw1, apdu.sw2);
769        if (r < 0) {
770                sc_debug(card->ctx, "Select_File[prefs_file]: card returned %d\n", r);
771                sc_unlock(card);
772                goto prefs_error;
773        }
774
775        r = iso_ops->read_binary(card, 0, prefs, sizeof(prefs), 0);
776        sc_unlock(card);
777        if (r <= 0) {
778                sc_debug(card->ctx, "Read_Binary[prefs_file] returned %d\n", r);
779                goto prefs_error;
780        }
781#if 0
782        dumphex("Prefs: ", prefs, r);
783#endif
784        i = get_pref(prefs, r, "[gen]", "lg", &len);
785        if (i <= 0 || len < 2) {
786                sc_debug(card->ctx, "Couldn't find language in prefs file: %d\n", i);
787                goto prefs_error;
788        }
789        lg_value = prefs + i;   /* language code(s) found, starts here */
790        i = 0;
791        while (1) {
792                while (i <= len - 2 && (lg_value[i] == ' ' || lg_value[i] == '|'))
793                        i++;
794                if (i > len - 2)
795                        goto prefs_error;
796                r = str2lang(card->ctx, lg_value + i);
797                if (r >= 0)
798                        return r;
799                i += 2;
800        }
801
802      prefs_error:
803        /* If troubles with the card's prefs file, get the language from the OS */
804#ifdef _WIN32
805        switch (GetUserDefaultLangID() & 0x00FF) {
806        case 0x13:
807                return LNG_DUTCH;
808        case 0x0C:
809                return LNG_FRENCH;
810        case 0x07:
811                return LNG_GERMAN;
812        default:
813                return LNG_ENG;
814        }
815#endif
816        return LNG_ENG;         /* default */
817}
818
819#endif  /* GET_LANG_FROM_CARD */
820
821static scconf_block *get_belpic_conf(sc_context_t *ctx, const char *name)
822{
823        scconf_block *conf_block = NULL, **blocks;
824        int i;
825
826        for (i = 0; ctx->conf_blocks[i] != NULL; i++) {
827                blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i], name, NULL);
828                if (!blocks)
829                        return NULL;
830                conf_block = blocks[0];
831                free(blocks);
832                if (conf_block != NULL)
833                        break;
834        }
835
836        return conf_block;
837}
838
839#ifdef BELPIC_PIN_PAD
840
841static void load_pin_pad_err(const char *reader_name, const char *pp_reader_lib, char *msg)
842{
843        char buf[300];
844        void *hDlg;
845
846        if (strlen(reader_name) + strlen(pp_reader_lib) > 200)
847                return;
848
849        sprintf(buf, "Error while loading library \"%s\" for pin pad reader \"%s\": %s\n",
850                pp_reader_lib, reader_name, msg);
851        scgui_ask_message(app_msg[0], "Pin pad library error", buf, btn_msg_close[0], NULL,
852                          reader_name);
853}
854
855static int belpic_load_pin_pad_lib(sc_card_t *card, struct belpic_priv_data *priv_data,
856                                   const char *reader_name, const char *pp_reader_lib)
857{
858        LONG r;
859        DWORD supported;
860
861        memset(priv_data->szPinPadDll, 0, sizeof(priv_data->szPinPadDll));
862        strcpy(priv_data->szPinPadDll, pp_reader_lib);
863
864        priv_data->scr_init = (FARPROC) SCR_SCardInit;
865        priv_data->scr_verify_pin = (FARPROC) SCR_SCardVerifyPIN;
866        priv_data->scr_change_pin = (FARPROC) SCR_SCardChangePIN;
867
868        if (priv_data->scr_init == NULL || priv_data->scr_verify_pin == NULL) {
869                sc_debug(card->ctx, "Function not found in \"%s\" err = 0x%0x\n",
870                         pp_reader_lib, GetLastError());
871                load_pin_pad_err(reader_name, pp_reader_lib,
872                                 "unsufficient functionality found in library");
873                return SC_ERROR_READER;
874        }
875
876        r = priv_data->scr_init(pp_reader_lib, reader_name, 1, &supported);
877        if (r != SCARD_S_SUCCESS) {
878                sc_debug(card->ctx, "SCR_Init() returned 0x%0x\n", r);
879                load_pin_pad_err(reader_name, pp_reader_lib, "Initialization of library failed");
880                return SC_ERROR_READER;
881        }
882        if (supported) {
883                sc_debug(card->ctx, "SCR_init() returned not supported code 0x%0x\n", supported);
884                load_pin_pad_err(reader_name, pp_reader_lib,
885                                 "Initialization of library returned UNSUPPORTED");
886                return SC_ERROR_READER;
887