source: trunk/src/ifd/ifd-cyberjack.c @ 1085

Revision 1085, 23.4 KB checked in by alonbl, 3 years ago (diff)

Fix memory leak in OpenCT/src/ifd/ifd-cyberjack.c

By Ludovic Rousseau with some modifications.

http://www.opensc-project.org/pipermail/opensc-devel/2008-December/011502.html

Line 
1/*____________________________________________________________________________
2        Cyberjack reader.
3       
4        Tested with USBID 0c4b:0100. These are red readers: one with LCD,
5        another one without.
6       
7        Supports PIN-pad authentication.
8
9        One advantage of this implementaiton is that everything needed to support
10        cyberjack is in this single file, as it is done for other OpenCT reader
11        drivers.
12
13        This code doesn't unload cyberjack kernel module, with which it will
14        conflict. To do this call "rmmod cyberjack" after the device is plugged in,
15        or better add "blacklist cyberjack" to modprobe.conf.
16       
17        TODO: cleanup improvised T=1 communication with the reader.
18
19        Written by Andrey Jivsov in 2006. opensc@brainhub.org or ajivsov@pgp.com
20
21        $Id: $
22____________________________________________________________________________*/
23
24#include "internal.h"
25#include "usb-descriptors.h"
26#include <stdlib.h>
27#include <string.h>
28#include <stdarg.h>
29#include <unistd.h>
30#include <stdio.h>
31#include "ctbcs.h"
32
33static const unsigned T1_I_SEQ_SHIFT=6;
34static const unsigned T1_R_SEQ_SHIFT=4;
35static const unsigned DATA_NAD = (0<<4/*card*/) | 2/*host*/;
36
37/* Pseudo-slot referencing the reader. The reader exposes only
38 * one slot corresponding to the card and is at index 0.
39 */
40static const int cyberjack_reader_slot = (OPENCT_MAX_SLOTS-1);
41static const int cyberjack_card_slot = 0;
42
43struct cyberjack_t1_state {
44        unsigned ns;
45        ifd_device_t * dev;
46        ifd_protocol_t *proto;
47        int verify_initiated;
48        int verify_timeout;             // in seconds
49};
50
51#if !defined(ifd_msleep) && !defined(BG_MODULE)
52#define ifd_msleep(x) usleep(x * 1000)
53#endif
54
55#if 1
56#define cyberjack_ct_error(max_len, fmt, args... ) \
57        ct_error( fmt, ##args );
58#else
59/* define your own here for testing */
60#define cyberjack_ct_error(max_len, fmt, args...) \
61        ct_error( max_len, fmt, ##args );
62#endif
63
64#if 1
65#define cyberjack_ifd_debug( level, max_len, args... )  \
66        ifd_debug( level, ##args )
67#else
68/* define your own here for testing */
69#define cyberjack_ifd_debug( level, max_len, args... )  \
70        ifd_debug( level, max_len, ##args )
71#endif
72
73static unsigned int get_checksum( void *p, int len )  {
74        int i;
75        unsigned char *pp = p;
76        unsigned ret=0;
77        for( i=0; i<len; i++ )
78                ret ^= pp[i];
79        return ret;
80}
81
82inline static unsigned get_nad_mirrow( unsigned nad )  {
83        return (((nad&0xf)<<4) | (nad>>4));
84}
85
86static int cyberjack_init_proto( ifd_reader_t *reader, struct cyberjack_t1_state *state )  {
87        ifd_protocol_t *p;     
88        if( state->proto==NULL )  {
89                p = ifd_protocol_new(IFD_PROTOCOL_T1, reader, DATA_NAD);
90                if (p == NULL)  {
91                        cyberjack_ct_error( 40, "cyberjack: internal error: cannot allocate protocol object" );
92                        return -1;
93                }
94                state->proto = p;
95        }
96        else  {
97                cyberjack_ct_error( 40, "cyberjack: internal error: protocol already initialized" );
98                return -1;
99        }
100        return 0;
101}
102
103static void cyberjack_free_proto( struct cyberjack_t1_state *state )  {
104        if( state->proto )
105                ifd_protocol_free( state->proto );
106}
107
108/*
109 * Initialize the device
110 */
111static int cyberjack_open(ifd_reader_t * reader, const char *device_name)
112{
113    ifd_device_t *dev;
114    struct ifd_usb_device_descriptor de;
115        ifd_device_params_t params;
116        const int device_name_len = strlen(device_name);
117        int ret;
118
119        (void)device_name_len;
120
121        cyberjack_ifd_debug(1, 40+device_name_len, "device=%s", device_name);
122         
123        reader->name = "cyberjack reader";
124        reader->nslots = cyberjack_card_slot + 1;
125       
126        if (!(dev = ifd_device_open(device_name)))
127                return -1;
128        if (ifd_device_type(dev) == IFD_DEVICE_TYPE_USB) {
129                if (ifd_usb_get_device(dev, &de)) {
130                        cyberjack_ct_error(80, "cyberjack: device descriptor not found");
131                        ifd_device_close(dev);
132                        return -1;
133                }
134       
135                if( de.idProduct == 0x100 )  {
136                        cyberjack_ct_error(80+device_name_len, "detected e-com/pp at %s, max packet %d\n", 
137                                device_name, de.bMaxPacketSize0);
138                       
139                        params = dev->settings;
140                       
141                        // doesn't seem to make the difference:
142                        params.usb.interface = 0;
143                        params.usb.altsetting = 0;
144                        params.usb.configuration = 1;
145
146                        cyberjack_ifd_debug(1, 80, "trying to claim interface %d on device, config %d",
147                                params.usb.interface, params.usb.configuration );
148               
149                        // for send
150                        params.usb.ep_o = 0x02; 
151                        params.usb.ep_i = 0x82;
152                        if (ifd_device_set_parameters(dev, &params) < 0) {
153                        cyberjack_ct_error(80+device_name_len, "cyberjack: setting parameters failed. Try /sbin/rmmod cyberjack first");
154                        ifd_device_close(dev);
155                        return -1;
156                        }
157                        cyberjack_ifd_debug(1, 80, "successfully claimed interface" );
158                }
159                else
160                        ret = -1;
161        }
162        else {
163                cyberjack_ct_error( 80+device_name_len, "cyberjack: device %s is not a USB device", device_name);
164                ifd_device_close(dev);
165                return -1;
166        }
167   
168        ifd_msleep( 200 );
169   
170        cyberjack_ifd_debug(1, 80, "cyberjack: returning device %p", dev );
171        reader->device = dev;
172   
173        // yes, it is definitely needed to reliably power-up the card
174        ifd_device_reset( dev );
175
176        return 0;
177}
178
179static int cyberjack_close(ifd_reader_t *reader)  {
180        free( reader->driver_data );
181        reader->driver_data = NULL;
182        return 0;
183}
184
185 // everything is fine, except first byte of T=1 indicates wrong sender or recipient                                   
186#define CJ_RCV_OTHER -1
187
188
189// convenience function to send T=1 datagram to the reader
190// t1_data_no_checksum is nad pcb len [body], i.e. T=1 datagram without the checksum
191// so we can calculate it depending on ns
192static int cyberjack_send_t1( struct cyberjack_t1_state *state, char *t1_data, int send_len )  {
193        unsigned char send_buffer[64];
194        int ret;
195        if( send_len > sizeof(send_buffer)-3 )
196                return -1;
197        memcpy( send_buffer+3, t1_data, send_len );
198        send_len++;     // for checksum
199        send_buffer[0] = 0;
200        send_buffer[1] = send_len & 0xff;
201        send_buffer[2] = send_len >> 8;
202        send_buffer[3+1] |= (state->ns << T1_I_SEQ_SHIFT);              // set the toggle
203        send_buffer[3+send_len-1] = get_checksum( send_buffer+3, send_len-1 );
204        ret = ifd_device_send( state->dev, send_buffer, send_len+3 );
205        if( ret < 0 )
206                return ret;
207        return ret-4;
208}
209
210/* send special S-Block reply */
211static int cyberjack_resync_t1(struct cyberjack_t1_state *state, unsigned char nad, unsigned cmd)  {
212        ifd_device_t * const dev = state->dev;
213        unsigned char send_buffer[64];
214        int ret;
215       
216        send_buffer[0] = 0;
217        send_buffer[1] = 4;
218        send_buffer[2] = 0;
219       
220        send_buffer[3] = get_nad_mirrow(nad);   // NAD for device communication
221        send_buffer[4] = cmd;
222        send_buffer[5] = 0;
223        send_buffer[6] = get_checksum(send_buffer+3, 3);
224               
225        ret = ifd_device_send( dev, send_buffer, 7 );
226        if( ret > 0 )
227                state->ns = 0;
228               
229        return ret;
230}
231
232/* doesn't seem to make the difference which values I put in timeouts,
233 * but the reply itself is necessary
234 */
235static int cyberjack_extend_t1(struct cyberjack_t1_state *state, const unsigned char *t1_in)  {
236        ifd_device_t * const dev = state->dev;
237        unsigned char send_buffer[64];
238        int len;
239
240        send_buffer[0] = 0;
241        send_buffer[2] = 0;
242       
243        send_buffer[3] = get_nad_mirrow(t1_in[0]);
244        if( t1_in[2]==0 )  {
245                send_buffer[1] = 4;
246
247                send_buffer[4] = 0xe3;
248                send_buffer[5] = 0;
249                send_buffer[6] = get_checksum(send_buffer+3, 3);
250                len = 3+4;
251        }
252        else  {
253                send_buffer[1] = 5;
254
255                send_buffer[4] = 0xe3;
256                send_buffer[5] = 1;
257                send_buffer[6] = t1_in[3];
258                send_buffer[7] = get_checksum(send_buffer+3, 4);
259                len = 3+5;
260        }
261       
262        return ifd_device_send( dev, send_buffer, len );
263}
264
265// the nad os for the previous send command
266static int cyberjack_recv_t1( struct cyberjack_t1_state *state, unsigned nad, unsigned char t1_out[64])  {
267        unsigned char read_buffer[64];
268        ifd_device_t * const dev = state->dev;
269        int ret=-1;
270       
271start:
272        if( (ret=ifd_device_recv( dev, read_buffer, 64, 8000 )) < 7 )  {
273                cyberjack_ct_error(80, "cyberjack: failed to activate 2");
274                return -1;
275        }
276        cyberjack_ifd_debug(1, 80+ret*3, "cyberjack: response %s", ct_hexdump( read_buffer, ret ));
277
278        if( read_buffer[0]!=0 || read_buffer[1]!=ret-3 || read_buffer[2]!=0 )  {
279                cyberjack_ifd_debug(1, 80, "cyberjack: wrong header");
280                return CJ_RCV_OTHER;
281        }
282       
283        if( get_checksum( read_buffer+3, ret-3 ) )  {
284                cyberjack_ifd_debug(1, 80, "cyberjack: checksum mismatch");
285                return CJ_RCV_OTHER;
286        }
287       
288        ret -= 3;
289       
290        memcpy( t1_out, read_buffer+3, ret );
291        cyberjack_ifd_debug(1, 80+ret*3, "cyberjack: returning %s", ct_hexdump( t1_out, ret ));
292
293        if( (t1_out[1]&0xC0)==0x80 ) {
294                cyberjack_ifd_debug(1, 40, "R-BLOCK");                 
295                if( ((t1_out[1] >> T1_R_SEQ_SHIFT) & 1) != state->ns )  {
296                                state->ns ^= 1;
297                                cyberjack_ifd_debug(1, 80, "*** cyberjack: switching ns to %d", state->ns); 
298                        }
299        }
300        if( (t1_out[1]&0x80)==0x00 ) {
301                cyberjack_ifd_debug(1, 40, "I-BLOCK");
302                state->ns ^= 1;
303                cyberjack_ifd_debug(1, 80, "*** cyberjack: switching ns to %d", state->ns); 
304        }
305        // S-BLOCK is (t1_out[1]&0xC0)==0xC0
306        switch( t1_out[1] ) {
307                case 0xc1:
308                        cyberjack_ifd_debug(1, 40, "S-BLOCK IFD request");
309                        break;
310                case 0xc2:
311                        cyberjack_ifd_debug(1, 40, "S-BLOCK Abort request");
312                        break;
313                case 0xc3:
314                        cyberjack_ifd_debug(1, 40, "S-BLOCK WTX request");
315                       
316                        ret = cyberjack_extend_t1( state, t1_out );
317                        if( ret < 0 )
318                                return ret;
319                        goto start;
320                       
321                        break;
322                case 0xe0:
323                        cyberjack_ifd_debug(1, 40, "S-BLOCK Resync response 2");
324                        break;
325                case 0xc0:
326                        cyberjack_ifd_debug(1, 40, "S-BLOCK Resync request");
327                        break;
328                case 0xc4:
329                case 0xf4:
330                        cyberjack_ifd_debug(1, 40, "S-BLOCK key pressed request");
331                        // reply
332                        ret = cyberjack_send_t1( state, "\xe2\xe4\x00", 3 );
333                        if( ret < 0 )
334                                return ret;
335                        goto start;
336
337                        break;
338                case 0xe6:
339                case 0xf6:
340                        cyberjack_ifd_debug(1, 40, "S-BLOCK to throw away");
341                        break;
342                case 0xe5:
343                case 0xf5:
344                        cyberjack_ifd_debug(1, 40, "S-BLOCK card (not) present");
345
346                        ret = cyberjack_resync_t1( state, t1_out[0], 0xd5 );
347                        if( ret < 0 )
348                                return ret;
349                        goto start;
350                       
351                        break;
352                default:
353                        if( (t1_out[1]&0xC0)==0xC0 )  {
354                                cyberjack_ifd_debug(1, 40, "unknown S-BLOCK");
355                        }
356                        break;
357        }
358
359        return ret;
360}
361
362/*
363 * Power up the reader
364 */
365static int cyberjack_activate(ifd_reader_t *reader)
366{
367    unsigned char read_buffer[64];
368    ifd_device_t * const dev = reader->device;
369        int ret;
370        int result = -1;
371        struct cyberjack_t1_state *state = NULL;
372 
373        cyberjack_ifd_debug(1, 40, "called (dev = 0x%x).", reader->device);
374
375        if( reader->driver_data )  {
376                cyberjack_free_proto( reader->driver_data );
377                free( reader->driver_data );
378                reader->driver_data = NULL;
379        }
380
381        state = calloc( 1, sizeof(struct cyberjack_t1_state) );
382        if( state == NULL )
383                goto cleanup;
384               
385        state->dev = dev;
386       
387        if( ifd_device_send( dev, (unsigned char*)"\x00\x04\x00" "\xe2\xc1\x00\x23", 7 ) != 7 ||
388            ifd_device_send( dev, (unsigned char*)"\x00\x04\x00" "\xe2\xc0\x00\x22", 7 ) != 7 )
389        {
390                cyberjack_ct_error(80, "cyberjack: failed to activate 1");
391                goto cleanup;
392        }
393       
394        ifd_msleep( 100 );
395        if( (ret=cyberjack_recv_t1( state, 0xe2, read_buffer ))!=4 || memcmp( read_buffer, "\x2e\xe0\x00\xce", 4 )!=0 )  {
396                cyberjack_ct_error(80, "cyberjack: failed to activate 2: no cookie");
397                goto cleanup;
398        }
399
400        // send 20 11 00 00
401        if( cyberjack_send_t1( state, "\x12\x00\x04" "\x20\x11\x00\x00", 7 ) != 7 )  {
402                cyberjack_ct_error(80, "cyberjack: failed to activate 5");             
403                goto cleanup;
404        }
405        ret = cyberjack_recv_t1( state, 0x12, read_buffer );
406        if( ret < 0 )  {
407                cyberjack_ct_error(80, "cyberjack: failed to activate 5.1");           
408                goto cleanup;
409        }
410        cyberjack_ifd_debug(1, 80+ret*3, "cyberjack: t1 response is : %s", 
411                        ct_hexdump( read_buffer, ret ));
412        if( ret < 6 )  {
413                cyberjack_ifd_debug(1, 80, "cyberjack: response is short 6.1");
414                goto cleanup;
415        }
416        if( ret != 6 || read_buffer[3]!=0x90 || read_buffer[4]!=0 )
417        {
418                cyberjack_ifd_debug(1, 80, "cyberjack: response to 20 11 00 00:  %s", 
419                        ct_hexdump( read_buffer, 6 ));
420                // could neever recover from this
421                cyberjack_ct_error(80, "cyberjack: failed to activate: failed to reset the reader");           
422                goto cleanup;
423        }
424
425        // The following is needed to transition from our protocol to
426        // CT's protocol object. What we want here is state->ns to turn 0
427        // so CT's T=1 protocol object can take over from here
428        ret = cyberjack_resync_t1( state, 0x2e, 0xc0/*request to resync*/ );
429        if( ret < 0 )  {
430                cyberjack_ct_error(80, "cyberjack: failed to activate in resync");             
431        }
432        ret = cyberjack_recv_t1( state, 0x2e, read_buffer );
433        if( ret < 3 || memcmp(read_buffer, "\x2e\xe0\x00", 3 )!=0 )  {
434                cyberjack_ct_error(80, "cyberjack: failed to activate 7.1");           
435                goto cleanup;
436        }
437       
438        reader->driver_data = state;
439        state = NULL;
440       
441        cyberjack_init_proto( reader, (struct cyberjack_t1_state *)reader->driver_data );
442       
443        cyberjack_ifd_debug(1, 80, "cyberjack: activated OK, ns=%d",
444                ((struct cyberjack_t1_state *)reader->driver_data)->ns);
445       
446        result = 0;
447
448cleanup:
449        if (state != NULL) {
450                free(state);
451        }
452
453        return result;
454}
455
456static int cyberjack_deactivate(ifd_reader_t * reader)
457{
458        struct cyberjack_t1_state *state = reader->driver_data;
459
460        cyberjack_ifd_debug(1, 40, "called.");
461
462        cyberjack_free_proto( state );
463        free( state );
464        reader->driver_data = NULL;
465
466    /* if there are some cards that are powered on, power them off */
467
468        return 0;
469}
470
471/*
472 * Card status - always present
473 */
474static int cyberjack_card_status(ifd_reader_t * reader, int slot, int *status)
475{
476        struct cyberjack_t1_state *state = reader->driver_data;
477        unsigned char response[64];
478        ifd_slot_t *pslot;
479        ifd_protocol_t *proto;
480        int ret;
481        unsigned stat;
482       
483        cyberjack_ifd_debug(1, 40, "slot=%d", slot);
484       
485        if( state==NULL || slot != cyberjack_card_slot )
486                return -1;
487
488        pslot = &reader->slot[slot];
489
490        if( pslot->proto )
491                proto = pslot->proto;
492        else
493                proto = state->proto;
494
495        // cyberjack_ifd_debug(1, 80, "proto=%p, pslot=%p, state=%p", proto, pslot, state);
496               
497        ret = ifd_protocol_transceive( proto, 0x12, "\x20\x13\x00\x80\x00", 5, 
498                response, sizeof(response) );
499        if( ret < 0 )  {
500                cyberjack_ct_error(80, "cyberjack: failed to get status");             
501                return ret;
502        }
503       
504        cyberjack_ifd_debug(1, 80+ret*3, "cyberjack: response to get status: %s", 
505                ct_hexdump( response, ret ));
506               
507        // saw this: 80 01 03 90 00 for inserted card
508        //           80 01 00 90 00 for removed
509        stat = (( ret > 3 && response[ret-2]==0x90 && response[ret-1]==0 && response[ret-3]!=0 ) ? IFD_CARD_PRESENT : 0);
510
511        if( !(stat & IFD_CARD_PRESENT) && pslot->proto )  {
512                cyberjack_ifd_debug(1, 80, "cyberjack: card removed");
513                /* hide protocol object from openct, or we will not be able to reset
514                 * re-inserted card.
515                 */
516                state->proto = pslot->proto;
517                pslot->proto = NULL;
518                stat |= IFD_CARD_STATUS_CHANGED;
519        }
520
521        *status = stat;
522        return 0;
523}
524
525/* this is when the light on the reader goes on */
526static int cyberjack_card_reset(ifd_reader_t * reader, int slot, void *atr,
527                                                         size_t size)
528{
529        unsigned char response[64];
530        struct cyberjack_t1_state * const state = (struct cyberjack_t1_state *)reader->driver_data;
531        ifd_slot_t *pslot; 
532        ifd_protocol_t *proto;
533        int ret;
534
535        cyberjack_ifd_debug(1, 40, "called.");
536
537        if( slot != cyberjack_card_slot )
538                return -1;
539       
540        pslot = &reader->slot[slot];
541
542        if( pslot->proto )
543                proto = pslot->proto;
544        else
545                proto = state->proto;
546
547        if( proto==NULL )  {
548                cyberjack_ifd_debug(1, 40, "cannot obtain protocol object, slot=%d", slot);
549                return -1;
550        }
551
552        // 0x14 here is timeout in secs.
553        ret = ifd_protocol_transceive( proto, 0x12, "\x20\x12\x01\x01\x01\x14\x00", 7, 
554                response, sizeof(response) );
555        if( ret < 0 )  {
556                cyberjack_ct_error(80, "cyberjack: failed to get ATR: err=%d", ret);           
557                return ret;
558        }
559       
560        cyberjack_ifd_debug(1, 80+ret*3, "cyberjack: response to get ATR: %s", 
561                ct_hexdump( response, ret ));
562
563        memcpy( atr, response, ret );
564
565        return ret;
566}
567
568static int cyberjack_set_protocol(ifd_reader_t * reader, int slot, int proto)
569{
570        ifd_slot_t *pslot;
571        struct cyberjack_t1_state * const state = (struct cyberjack_t1_state *)reader->driver_data;
572
573        cyberjack_ifd_debug(1, 40, "slot=%d", slot);
574
575        if( slot != cyberjack_card_slot )
576                return -1;
577
578        if (proto != IFD_PROTOCOL_T1 && proto != IFD_PROTOCOL_T0 ) {
579                cyberjack_ct_error(80+strlen(reader->name), "%s: protocol %d not supported", reader->name, proto);
580                return IFD_ERROR_NOT_SUPPORTED;
581        }
582        pslot = &reader->slot[slot];
583       
584        // this is actually used as (dad<<4 | sad) inside
585        // the reply is never checked and is expected to be the 4 bit flipped version
586        pslot->dad = DATA_NAD;
587
588        /* Protocol is already allocated. Detach it from the state and attach to the slot
589         * for CT to use it. */
590        if( state->proto == NULL )  {   
591                cyberjack_ct_error( 40+strlen(reader->name), "%s: internal error", reader->name);
592                return IFD_ERROR_GENERIC;
593        }
594        if (pslot->proto) {
595                ifd_protocol_free(pslot->proto);
596                pslot->proto = NULL;
597        }
598        pslot->proto = state->proto;
599        state->proto = NULL;
600
601        // To simulate communication stall (not USB stall) comment these out.
602        // You will get S-BLOCK T=1 response that the core cannot handle...
603        ifd_protocol_set_parameter(pslot->proto, IFD_PROTOCOL_T1_IFSD, 254);
604        cyberjack_ifd_debug(1, 80, "set protocol's IFSd size to %d", 254);
605        ifd_protocol_set_parameter(pslot->proto, IFD_PROTOCOL_T1_IFSC, 254);
606        cyberjack_ifd_debug(1, 80, "set protocol's IFSc size to %d",254);
607
608        return 0;
609}
610
611
612static int cyberjack_send(ifd_reader_t *reader, unsigned int dad,
613                     const unsigned char *buffer, size_t len)
614{
615        unsigned char request[512];
616    ifd_device_t * const dev = reader->device;
617        int ret;
618       
619        cyberjack_ifd_debug(1, 40, "called with dad=%02x, len=%d", dad, len);   
620       
621        if( len > sizeof(request)-3 )  {
622                cyberjack_ct_error(80+strlen(reader->name), "%s: request length too large: %d", reader->name, len);
623                return -1;
624        }
625       
626        request[0] = 0;
627        request[1] = len & 0xff;
628        request[2] = len >> 8;
629 
630        len+=3;
631
632        memcpy( request+3, buffer, len );
633
634        ret = ifd_device_send( dev, request, len );
635
636        return ret;
637}
638
639/* TODO: working on generatlization of time with ifd_time, ifd_get_current_time, ifd_time_elapsed2 */
640struct ifd_time  {
641        unsigned p1;
642        unsigned p2;    /* These must be opaque */
643};
644/* a wrapper so both are in one place */
645static void ifd_get_current_time( struct ifd_time *now )  {
646        struct timeval now_tv;
647
648        gettimeofday(&now_tv, NULL);
649
650        now->p1 = now_tv.tv_sec;
651        now->p2 = now_tv.tv_usec;
652}
653static long ifd_time_elapsed2( struct ifd_time *then )
654{
655        struct timeval now, delta, then_tv;
656        long l;
657
658//ct_debug(40, "ifd_time_elapsed2");
659        then_tv.tv_sec = then->p1;
660        then_tv.tv_usec = then->p2;
661
662        gettimeofday(&now, NULL);
663        timersub(&now, &then_tv, &delta);
664        l = delta.tv_sec * 1000 + (delta.tv_usec / 1000);
665//ct_debug(40, "ifd_time_elapsed2 returns %ld", l);
666        return l;
667}
668
669/* TODO: we need to loop here to make sure we are buffering the whole response
670 * before parsing it. */
671static int cyberjack_recv(ifd_reader_t *reader, unsigned int dad,
672                     unsigned char *buffer, size_t len, long timeout)
673{
674    unsigned char response[512];
675        unsigned response_size=0;
676    ifd_device_t * const dev = reader->device;
677        struct cyberjack_t1_state * const state = (struct cyberjack_t1_state *)reader->driver_data;
678        int tries;
679        int ret;
680        struct ifd_time time_start;
681        long deadline;
682
683        cyberjack_ifd_debug(1, 40, "called with dad=%02x, len=%d", dad, len);   
684
685        if( len > sizeof(response)-3 )  {
686                cyberjack_ct_error(80, "cyberjack: response length too large: %d", len);
687                return -1;
688        }
689
690        /* some upper bound number that we hope we will not hit:
691         * more for operations involving user interaction
692         */
693        tries = (state->verify_initiated ? 100 : 20);
694       
695        ifd_get_current_time( &time_start );
696
697        /* in ms; 110% of requested time to let the reader fail instead of us
698         */
699        deadline = state->verify_timeout*1100;
700       
701        while( tries-- )  {
702                response_size = len+3;
703               
704                if( state->verify_initiated && ifd_time_elapsed2( &time_start ) > deadline )  {
705                        cyberjack_ct_error(80, "cyberjack: cannot complete verify operation in %d seconds", 
706                                deadline/1000 );
707                        return IFD_ERROR_TIMEOUT;
708                }
709       
710                ret = ifd_device_recv( dev, response, response_size, timeout );
711                if( ret < 0 )
712                        return ret;
713       
714        //      cyberjack_ifd_debug(1, 80, "cyberjack: response %s", ct_hexdump( response, ret ) );
715       
716                if( ret < 3+4 || response[0] != 0 ) {
717                        cyberjack_ct_error(80, "cyberjack: response %s is too short", ct_hexdump( response, ret ) );
718                        break; // pass through // return IFD_ERROR_GENERIC;
719                }
720       
721                response_size = response[1] | (response[2]<<8);
722                if( response_size != ret-3 )    {
723                        cyberjack_ifd_debug(1, 80+ret*3, "cyberjack: inconsistent length in response %s", ct_hexdump( response, ret ));
724                        break;  // pass through
725                }
726       
727                /* This is urgly. We need to watch for a few proprietary S-BLOCKS that
728                 * core CT protocol handler cannot handle. Fortunately, we don't neet to
729                 * maintain the nabble for these. */
730                switch( response[3+1] )  {
731                case 0xf4:      // key pressed (OK key)
732                case 0xc4:      // key pressed (digit keys)
733                        cyberjack_ifd_debug(1, 80, "cyberjack: key pressed");
734                        ret = cyberjack_send_t1( state, "\xe2\xe4\x00", 3 );
735                        if( ret < 0 )
736                                return ret;
737                        continue;       /* re-read again */
738                case 0xc3:      // WTX
739                        cyberjack_ifd_debug(1, 80, "timeout, grant extension, %d tries remains", tries);               
740                        ret = cyberjack_extend_t1( state, response+3 );
741                        if( ret < 0 )
742                                        return ret;
743                        continue;       /* re-read again */
744                }
745               
746                break;  // pass through
747        }
748       
749        memcpy( buffer, response+3, response_size );
750       
751        return response_size;
752}
753
754/*
755 * Perform a PIN verification.
756 * Timeout in seconds.
757 */
758static int cyberjack_perform_verify(ifd_reader_t * reader, int slot,
759                               unsigned int timeout, const char *prompt,
760                               const unsigned char *data, size_t data_len,
761                               unsigned char *resp, size_t resp_len)
762{
763        unsigned char buffer[256];
764        unsigned short sw;
765        ifd_slot_t *pslot;
766        struct cyberjack_t1_state * const state = (struct cyberjack_t1_state *)reader->driver_data;
767        int err;
768
769        if( slot != cyberjack_card_slot || state==NULL )
770                return -1;
771
772        pslot = &reader->slot[slot];
773       
774        cyberjack_ifd_debug(1, 40, "cyberjack: perform_verify timeout=%d", timeout);           
775
776        if( timeout==0 )
777                timeout = 30;
778
779#if 1
780        err = ctbcs_build_perform_verify_apdu(buffer, sizeof(buffer),
781                                            slot + 1, prompt, timeout,
782                                            data, data_len);
783        if (err < 0)
784                return err;
785#else
786        {
787                ct_buf_t buf;
788
789                ct_buf_init(&buf, buffer, sizeof(buffer));
790                ctbcs_begin(&buf, 0x18, slot+1, 0x00);
791
792                ct_buf_putc(&buf, 0x52);
793                ct_buf_putc(&buf, data_len);
794                ct_buf_put(&buf, data, data_len);
795
796                ctbcs_add_timeout(&buf, 0x80 /*timeout*/);
797
798                if (ct_buf_overrun(&buf))
799                        return IFD_ERROR_BUFFER_TOO_SMALL;
800
801                buffer[4] = ct_buf_avail(&buf) - 5;     /* lc */
802                err = ct_buf_avail(&buf);
803        }
804#endif
805
806        state->verify_initiated = 1;
807        state->verify_timeout = timeout;
808
809        /* fetch the protocol object directly because we want to use another NAD */
810        err = ifd_protocol_transceive(pslot->proto, 0x12, buffer, err, resp, resp_len);
811
812        state->verify_initiated = 0;
813
814        if (err < 0) {
815                cyberjack_ct_error(80, "perform_verify failed with err=%d", err);
816                return err;
817        }
818       
819        if( err < 2 )
820                return IFD_ERROR_COMM_ERROR;
821        sw = (resp[err-2] << 8) | resp[err-1];
822       
823        cyberjack_ct_error(80, "perform_verify: err=%d sw=%04x", err, (unsigned)sw);   
824
825        if( sw >= 0x6300 && sw < 0x63cf )
826                sw &= 0xff00;
827
828        ifd_msleep(500);
829
830        switch (sw) {
831        case 0x6400:
832                cyberjack_ct_error(80, "perform_verify failed: timeout");
833                return IFD_ERROR_USER_TIMEOUT;
834        case 0x6401:
835                cyberjack_ct_error(80, "perform_verify failed: user pressed cancel");
836                return IFD_ERROR_USER_ABORT;
837        case 0x6300:
838                cyberjack_ct_error(80, "perform_verify failed: PIN mismatch");
839                return IFD_ERROR_PIN_MISMATCH;
840        }
841
842        return 2;
843}
844
845/*
846 * Driver operations
847 */
848static struct ifd_driver_ops cyberjack_driver;
849
850/*
851 * Initialize this module
852 */
853void ifd_cyberjack_register(void)
854{
855        cyberjack_driver.open = cyberjack_open;
856        cyberjack_driver.activate = cyberjack_activate;
857        cyberjack_driver.deactivate = cyberjack_deactivate;
858       
859        cyberjack_driver.card_status = cyberjack_card_status;
860        cyberjack_driver.card_reset = cyberjack_card_reset;
861        cyberjack_driver.set_protocol = cyberjack_set_protocol;
862        cyberjack_driver.send = cyberjack_send;
863        cyberjack_driver.recv = cyberjack_recv;
864        cyberjack_driver.close = cyberjack_close;
865        cyberjack_driver.perform_verify = cyberjack_perform_verify;
866
867        ifd_driver_register("cyberjack", &cyberjack_driver);
868}
Note: See TracBrowser for help on using the repository browser.