source: trunk/src/ifd/proto-t1.c @ 1127

Revision 1127, 13.2 KB checked in by ludovic.rousseau, 3 years ago (diff)

use #defined named NAD, PCB, LEN and DATA instead of hard coded numbers

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * Implementation of T=1
3 *
4 * Copyright (C) 2003, Olaf Kirch <okir@suse.de>
5 *
6 * improvements by:
7 * Copyright (C) 2004 Ludovic Rousseau <ludovic.rousseau@free.fr>
8 */
9
10#include "internal.h"
11#include <sys/poll.h>
12#include <unistd.h>
13#include <stdlib.h>
14#include <string.h>
15
16typedef struct {
17        ifd_protocol_t base;
18        int state;
19        int block_oriented;
20
21        unsigned char ns;
22        unsigned char nr;
23        unsigned int ifsc;
24        unsigned int ifsd;
25
26        unsigned int timeout, wtx;
27        unsigned int retries;
28        unsigned int rc_bytes;
29
30        unsigned int (*checksum) (const unsigned char *,
31                                  size_t, unsigned char *);
32} t1_state_t;
33
34/* T=1 protocol constants */
35#define T1_I_BLOCK              0x00
36#define T1_R_BLOCK              0x80
37#define T1_S_BLOCK              0xC0
38#define T1_MORE_BLOCKS          0x20
39
40/* I block */
41#define T1_I_SEQ_SHIFT          6
42
43/* R block */
44#define T1_IS_ERROR(pcb)        ((pcb) & 0x0F)
45#define T1_EDC_ERROR            0x01
46#define T1_OTHER_ERROR          0x02
47#define T1_R_SEQ_SHIFT          4
48
49/* S block stuff */
50#define T1_S_IS_RESPONSE(pcb)   ((pcb) & T1_S_RESPONSE)
51#define T1_S_TYPE(pcb)          ((pcb) & 0x0F)
52#define T1_S_RESPONSE           0x20
53#define T1_S_RESYNC             0x00
54#define T1_S_IFS                0x01
55#define T1_S_ABORT              0x02
56#define T1_S_WTX                0x03
57
58#define T1_BUFFER_SIZE          (3 + 254 + 2)
59
60#define NAD 0
61#define PCB 1
62#define LEN 2
63#define DATA 3
64
65/* internal state, do not mess with it. */
66/* should be != DEAD after reset/init */
67enum {
68        SENDING, RECEIVING, RESYNCH, DEAD
69};
70
71static void t1_set_checksum(t1_state_t *, int);
72static unsigned int t1_block_type(unsigned char);
73static unsigned int t1_seq(unsigned char);
74static unsigned int t1_build(t1_state_t *, unsigned char *,
75                             unsigned char, unsigned char,
76                             ct_buf_t *, size_t *);
77static unsigned int t1_compute_checksum(t1_state_t *, unsigned char *, size_t);
78static int t1_verify_checksum(t1_state_t *, unsigned char *, size_t);
79static int t1_xcv(t1_state_t *, unsigned char *, size_t, size_t);
80
81/*
82 * Set default T=1 protocol parameters
83 */
84static void t1_set_defaults(t1_state_t * t1)
85{
86        t1->retries = 3;
87        /* This timeout is rather insane, but we need this right now
88         * to support cryptoflex keygen */
89        t1->timeout = 20000;
90        t1->ifsc = 32;
91        t1->ifsd = 32;
92        t1->nr = 0;
93        t1->ns = 0;
94        t1->wtx = 0;
95}
96
97static void t1_set_checksum(t1_state_t * t1, int csum)
98{
99        switch (csum) {
100        case IFD_PROTOCOL_T1_CHECKSUM_LRC:
101                t1->rc_bytes = 1;
102                t1->checksum = csum_lrc_compute;
103                break;
104        case IFD_PROTOCOL_T1_CHECKSUM_CRC:
105                t1->rc_bytes = 2;
106                t1->checksum = csum_crc_compute;
107                break;
108        }
109}
110
111/*
112 * Attach t1 protocol
113 */
114static int t1_init(ifd_protocol_t * prot)
115{
116        t1_state_t *t1 = (t1_state_t *) prot;
117
118        t1_set_defaults(t1);
119        t1_set_checksum(t1, IFD_PROTOCOL_T1_CHECKSUM_LRC);
120
121        /* If the device is attached through USB etc, assume the
122         * device will do the framing for us */
123        if (prot->reader->device->type != IFD_DEVICE_TYPE_SERIAL)
124                t1->block_oriented = 1;
125        return 0;
126}
127
128/*
129 * Detach t1 protocol
130 */
131static void t1_release(ifd_protocol_t * prot)
132{
133        /* NOP */
134}
135
136/*
137 * Get/set parmaters for T1 protocol
138 */
139static int t1_set_param(ifd_protocol_t * prot, int type, long value)
140{
141        t1_state_t *t1 = (t1_state_t *) prot;
142
143        switch (type) {
144        case IFD_PROTOCOL_RECV_TIMEOUT:
145                t1->timeout = value;
146                break;
147        case IFD_PROTOCOL_BLOCK_ORIENTED:
148                t1->block_oriented = value;
149                break;
150        case IFD_PROTOCOL_T1_CHECKSUM_LRC:
151        case IFD_PROTOCOL_T1_CHECKSUM_CRC:
152                t1_set_checksum(t1, type);
153                break;
154        case IFD_PROTOCOL_T1_IFSC:
155                t1->ifsc = value;
156                break;
157        case IFD_PROTOCOL_T1_IFSD:
158                t1->ifsd = value;
159                break;
160        default:
161                ct_error("Unsupported parameter %d", type);
162                return -1;
163        }
164
165        return 0;
166}
167
168static int t1_get_param(ifd_protocol_t * prot, int type, long *result)
169{
170        t1_state_t *t1 = (t1_state_t *) prot;
171        long value;
172
173        switch (type) {
174        case IFD_PROTOCOL_RECV_TIMEOUT:
175                value = t1->timeout;
176                break;
177        case IFD_PROTOCOL_BLOCK_ORIENTED:
178                value = t1->block_oriented;
179                break;
180        default:
181                ct_error("Unsupported parameter %d", type);
182                return -1;
183        }
184
185        if (result)
186                *result = value;
187
188        return 0;
189}
190
191/*
192 * Send an APDU through T=1
193 */
194static int t1_transceive(ifd_protocol_t * prot, int dad, const void *snd_buf,
195                         size_t snd_len, void *rcv_buf, size_t rcv_len)
196{
197        t1_state_t *t1 = (t1_state_t *) prot;
198        ct_buf_t sbuf, rbuf, tbuf;
199        unsigned char sdata[T1_BUFFER_SIZE], sblk[5];
200        unsigned int slen, retries, resyncs, sent_length = 0;
201        size_t last_send = 0;
202
203        if (snd_len == 0)
204                return -1;
205
206        /* we can't talk to a dead card / reader. Reset it! */
207        if (t1->state == DEAD)
208                return -1;
209
210        t1->state = SENDING;
211        retries = t1->retries;
212        resyncs = 3;
213
214        /* Initialize send/recv buffer */
215        ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
216        ct_buf_init(&rbuf, rcv_buf, rcv_len);
217
218        /* Send the first block */
219        slen = t1_build(t1, sdata, dad, T1_I_BLOCK, &sbuf, &last_send);
220
221        while (1) {
222                unsigned char pcb;
223                int n;
224
225                retries--;
226
227                if ((n = t1_xcv(t1, sdata, slen, sizeof(sdata))) < 0) {
228                        ifd_debug(1, "fatal: transmit/receive failed");
229                        t1->state = DEAD;
230                        goto error;
231                }
232
233                if (!t1_verify_checksum(t1, sdata, n)) {
234                        ifd_debug(1, "checksum failed");
235                        if (retries == 0 || sent_length)
236                                goto resync;
237                        slen = t1_build(t1, sdata,
238                                        dad, T1_R_BLOCK | T1_EDC_ERROR,
239                                        NULL, NULL);
240                        continue;
241                }
242
243                pcb = sdata[PCB];
244                switch (t1_block_type(pcb)) {
245                case T1_R_BLOCK:
246                        if (T1_IS_ERROR(pcb)) {
247                                ifd_debug(1, "received error block, err=%d",
248                                          T1_IS_ERROR(pcb));
249                                goto resync;
250                        }
251
252                        if (t1->state == RECEIVING) {
253                                slen = t1_build(t1, sdata,
254                                                dad, T1_R_BLOCK, NULL, NULL);
255                                break;
256                        }
257
258                        /* If the card terminal requests the next
259                         * sequence number, it received the previous
260                         * block successfully */
261                        if (t1_seq(pcb) != t1->ns) {
262                                ct_buf_get(&sbuf, NULL, last_send);
263                                sent_length += last_send;
264                                last_send = 0;
265                                t1->ns ^= 1;
266                        }
267
268                        /* If there's no data available, the ICC
269                         * shouldn't be asking for more */
270                        if (ct_buf_avail(&sbuf) == 0)
271                                goto resync;
272
273                        slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
274                                        &sbuf, &last_send);
275                        break;
276
277                case T1_I_BLOCK:
278                        /* The first I-block sent by the ICC indicates
279                         * the last block we sent was received successfully. */
280                        if (t1->state == SENDING) {
281                                ct_buf_get(&sbuf, NULL, last_send);
282                                last_send = 0;
283                                t1->ns ^= 1;
284                        }
285
286                        t1->state = RECEIVING;
287
288                        /* If the block sent by the card doesn't match
289                         * what we expected it to send, reply with
290                         * an R block */
291                        if (t1_seq(pcb) != t1->nr) {
292                                slen = t1_build(t1, sdata, dad,
293                                                T1_R_BLOCK | T1_OTHER_ERROR,
294                                                NULL, NULL);
295                                continue;
296                        }
297
298                        t1->nr ^= 1;
299
300                        if (ct_buf_put(&rbuf, sdata + 3, sdata[LEN]) < 0)
301                                goto error;
302
303                        if ((pcb & T1_MORE_BLOCKS) == 0)
304                                goto done;
305
306                        slen = t1_build(t1, sdata, dad, T1_R_BLOCK, NULL, NULL);
307                        break;
308
309                case T1_S_BLOCK:
310                        if (T1_S_IS_RESPONSE(pcb) && t1->state == RESYNCH) {
311                                t1->state = SENDING;
312                                sent_length = 0;
313                                last_send = 0;
314                                resyncs = 3;
315                                retries = t1->retries;
316                                ct_buf_init(&rbuf, rcv_buf, rcv_len);
317                                slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
318                                                &sbuf, &last_send);
319                                continue;
320                        }
321
322                        if (T1_S_IS_RESPONSE(pcb))
323                                goto resync;
324
325                        ct_buf_init(&tbuf, sblk, sizeof(sblk));
326
327                        switch (T1_S_TYPE(pcb)) {
328                        case T1_S_RESYNC:
329                                /* the card is not allowed to send a resync. */
330                                goto resync;
331                        case T1_S_ABORT:
332                                ifd_debug(1, "abort requested");
333                                break;
334                        case T1_S_IFS:
335                                ifd_debug(1, "CT sent S-block with ifs=%u",
336                                          sdata[DATA]);
337                                if (sdata[DATA] == 0)
338                                        goto resync;
339                                t1->ifsc = sdata[DATA];
340                                ct_buf_putc(&tbuf, sdata[DATA]);
341                                break;
342                        case T1_S_WTX:
343                                /* We don't handle the wait time extension
344                                 * yet */
345                                ifd_debug(1, "CT sent S-block with wtx=%u",
346                                          sdata[DATA]);
347                                t1->wtx = sdata[DATA];
348                                ct_buf_putc(&tbuf, sdata[DATA]);
349                                break;
350                        default:
351                                ct_error("T=1: Unknown S block type 0x%02x",
352                                         T1_S_TYPE(pcb));
353                                goto resync;
354                        }
355
356                        slen = t1_build(t1, sdata, dad,
357                                        T1_S_BLOCK | T1_S_RESPONSE |
358                                        T1_S_TYPE(pcb), &tbuf, NULL);
359                }
360
361                /* Everything went just splendid */
362                retries = t1->retries;
363                continue;
364
365              resync:
366                /* the number or resyncs is limited, too */
367                if (resyncs == 0)
368                        goto error;
369                resyncs--;
370                t1->ns = 0;
371                t1->nr = 0;
372                slen = t1_build(t1, sdata, dad, T1_S_BLOCK | T1_S_RESYNC, NULL,
373                                NULL);
374                t1->state = RESYNCH;
375                continue;
376        }
377
378      done:
379        return ct_buf_avail(&rbuf);
380
381      error:
382        t1->state = DEAD;
383        return -1;
384}
385
386static int t1_resynchronize(ifd_protocol_t * p, int nad)
387{
388        t1_state_t *t1 = (t1_state_t *) p;
389        unsigned char block[4];
390        unsigned int retries = 3;
391
392        if (p->reader && p->reader->device)
393                ifd_device_flush(p->reader->device);
394
395        while (retries--) {
396                t1->ns = 0;
397                t1->nr = 0;
398
399                block[0] = nad;
400                block[1] = T1_S_BLOCK | T1_S_RESYNC;
401                block[2] = 0;
402                t1_compute_checksum(t1, block, 3);
403
404                if (t1_xcv(t1, block, 4, sizeof(block)) != 4) {
405                        ifd_debug(1, "fatal: transmit/receive failed");
406                        break;
407                }
408
409                if (!t1_verify_checksum(t1, block, 4)) {
410                        ifd_debug(1, "checksum failed");
411                        continue;
412                }
413
414                if (block[1] == (T1_S_BLOCK | T1_S_RESPONSE | T1_S_RESYNC))
415                        return 0;
416        }
417
418        t1->state = DEAD;
419        return -1;
420}
421
422static unsigned t1_block_type(unsigned char pcb)
423{
424        switch (pcb & 0xC0) {
425        case T1_R_BLOCK:
426                return T1_R_BLOCK;
427        case T1_S_BLOCK:
428                return T1_S_BLOCK;
429        default:
430                return T1_I_BLOCK;
431        }
432}
433
434static unsigned int t1_seq(unsigned char pcb)
435{
436        switch (pcb & 0xC0) {
437        case T1_R_BLOCK:
438                return (pcb >> T1_R_SEQ_SHIFT) & 1;
439        case T1_S_BLOCK:
440                return 0;
441        default:
442                return (pcb >> T1_I_SEQ_SHIFT) & 1;
443        }
444}
445
446static unsigned int t1_build(t1_state_t * t1, unsigned char *block,
447                             unsigned char dad, unsigned char pcb,
448                             ct_buf_t * bp, size_t * lenp)
449{
450        unsigned int len;
451
452        len = bp ? ct_buf_avail(bp) : 0;
453        if (len > t1->ifsc) {
454                pcb |= T1_MORE_BLOCKS;
455                len = t1->ifsc;
456        }
457
458        /* Add the sequence number */
459        switch (t1_block_type(pcb)) {
460        case T1_R_BLOCK:
461                pcb |= t1->nr << T1_R_SEQ_SHIFT;
462                break;
463        case T1_I_BLOCK:
464                pcb |= t1->ns << T1_I_SEQ_SHIFT;
465                break;
466        }
467
468        block[0] = dad;
469        block[1] = pcb;
470        block[2] = len;
471
472        if (len)
473                memcpy(block + 3, ct_buf_head(bp), len);
474        if (lenp)
475                *lenp = len;
476
477        return t1_compute_checksum(t1, block, len + 3);
478}
479
480/*
481 * Protocol struct
482 */
483struct ifd_protocol_ops ifd_protocol_t1 = {
484        IFD_PROTOCOL_T1,        /* id */
485        "T=1",                  /* name */
486        sizeof(t1_state_t),     /* size */
487        t1_init,                /* init */
488        t1_release,             /* release */
489        t1_set_param,           /* set_param */
490        t1_get_param,           /* get_param */
491        t1_resynchronize,       /* resynchronize */
492        t1_transceive,          /* transceive */
493        NULL,                   /* sync_read */
494        NULL,                   /* sync_write */
495};
496
497/*
498 * Build/verify checksum
499 */
500static unsigned int t1_compute_checksum(t1_state_t * t1, unsigned char *data,
501                                        size_t len)
502{
503        return len + t1->checksum(data, len, data + len);
504}
505
506static int t1_verify_checksum(t1_state_t * t1, unsigned char *rbuf, size_t len)
507{
508        unsigned char csum[2];
509        int m, n;
510
511        m = len - t1->rc_bytes;
512        n = t1->rc_bytes;
513
514        if (m < 0)
515                return 0;
516
517        t1->checksum(rbuf, m, csum);
518        if (!memcmp(rbuf + m, csum, n))
519                return 1;
520
521        return 0;
522}
523
524/*
525 * Send/receive block
526 */
527static int t1_xcv(t1_state_t * t1, unsigned char *block, size_t slen,
528                  size_t rmax)
529{
530        ifd_protocol_t *prot = &t1->base;
531        unsigned int rlen, timeout;
532        int n, m;
533
534        if (ct_config.debug >= 3)
535                ifd_debug(3, "sending %s", ct_hexdump(block, slen));
536
537        n = ifd_send_command(prot, block, slen);
538        if (n < 0)
539                return n;
540
541        /* Maximum amount of data we'll receive - some devices
542         * such as the eToken need this. If you request more, it'll
543         * just barf */
544        rlen = 3 + t1->ifsd + t1->rc_bytes;
545
546        /* timeout. For now our WTX treatment is very dumb */
547        timeout = t1->timeout + 1000 * t1->wtx;
548        t1->wtx = 0;
549
550        if (t1->block_oriented) {
551                /* Note - Linux USB seems to have an off by one error, you
552                 * actually need the + 1 to get the RC byte */
553                rlen++;
554                if (rlen < rmax)
555                        rmax = rlen;
556
557                /* Get the response en bloc */
558                n = ifd_recv_response(prot, block, rmax, timeout);
559                if (n >= 0) {
560                        m = block[2] + 3 + t1->rc_bytes;
561                        if (m < n)
562                                n = m;
563                }
564        } else {
565                /* Get the header */
566                if (ifd_recv_response(prot, block, 3, timeout) < 0)
567                        return -1;
568
569                n = block[2] + t1->rc_bytes;
570                if (n + 3 > rmax || block[2] >= 254) {
571                        ct_error("receive buffer too small");
572                        return -1;
573                }
574
575                /* Now get the rest */
576                if (ifd_recv_response(prot, block + 3, n, t1->timeout) < 0)
577                        return -1;
578
579                n += 3;
580        }
581
582        if (n >= 0 && ct_config.debug >= 3)
583                ifd_debug(3, "received %s", ct_hexdump(block, n));
584
585        return n;
586}
587
588int t1_negotiate_ifsd(ifd_protocol_t * proto, unsigned int dad, int ifsd)
589{
590        t1_state_t *t1 = (t1_state_t *) proto;
591        ct_buf_t sbuf;
592        unsigned char sdata[T1_BUFFER_SIZE];
593        unsigned int slen;
594        unsigned int retries;
595        size_t snd_len;
596        int n;
597        unsigned char snd_buf[1], pcb;
598
599        retries = t1->retries;
600
601        /* S-block IFSD request */
602        snd_buf[0] = ifsd;
603        snd_len = 1;
604
605        /* Initialize send/recv buffer */
606        ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
607
608        while (1) {
609                /* Build the block */
610                slen =
611                    t1_build(t1, sdata, dad, T1_S_BLOCK | T1_S_IFS, &sbuf,
612                             NULL);
613
614                if ((n = t1_xcv(t1, sdata, slen, sizeof(sdata))) < 0) {
615                        ifd_debug(1, "fatal: transmit/receive failed");
616                        t1->state = DEAD;
617                        goto error;
618                }
619
620                if (!t1_verify_checksum(t1, sdata, n)) {
621                        ifd_debug(1, "checksum failed");
622                        if (retries == 0)
623                                goto error;
624                        continue;
625                }
626                pcb = sdata[1];
627                if (t1_block_type(pcb) == T1_S_BLOCK &&
628                    T1_S_TYPE(pcb) == T1_S_IFS && T1_S_IS_RESPONSE(pcb)) {
629                        if (sdata[LEN] != 1 || sdata[DATA] != ifsd)
630                                goto error;
631                        break;
632                }
633                if (retries == 0)
634                        goto error;
635        }
636
637        return n;
638
639      error:
640        t1_resynchronize(proto, dad);
641        return -1;
642}
Note: See TracBrowser for help on using the repository browser.