source: trunk/src/ifd/atr.c @ 1172

Revision 1172, 3.7 KB checked in by aj, 2 years ago (diff)

Enable cards without TDx entries to work - e.g. RSA SecureID 800.
Patch by Andrey Jivsov

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * ATR parsing functions
3 *
4 * Copyright (C) 2004, Olaf Kirch <okir@suse.de>
5 */
6
7#include "internal.h"
8#include <string.h>
9#include "atr.h"
10
11int ifd_atr_parse(ifd_atr_info_t * info, const unsigned char *atr, size_t len)
12{
13        unsigned int m, n, k;
14
15        ifd_debug(1, "atr=%s", ct_hexdump(atr, len));
16
17        /* Initialize the atr_info struct */
18        memset(info, 0, sizeof(*info));
19        info->default_protocol = -1;
20        for (n = 0; n < 3; n++) {
21                info->TA[n] = -1;
22                info->TB[n] = -1;
23                info->TC[n] = -1;
24        }
25
26        if (len < 2 + (atr[1] & 0x0f))
27                return IFD_ERROR_INVALID_ATR;
28
29        /* Ignore hysterical bytes */
30        len -= atr[1] & 0x0f;
31
32        for (m = 0, n = 2; n < len; m++) {
33                unsigned int TDi;
34
35                /* TA1, TA2, TA3, TA4 are legal, TA5 wouldn't be */
36                if (m > 3)
37                        return IFD_ERROR_INVALID_ATR;
38
39                TDi = atr[n - 1];
40                if (n != 2) {
41                        int prot;
42
43                        prot = TDi & 0x0f;
44                        if (info->default_protocol < 0)
45                                info->default_protocol = prot;
46                        info->supported_protocols |= (1 << prot);
47                }
48
49                k = ifd_count_bits(TDi & 0xF0);
50                if (k == 0 || n + k > len)
51                        return IFD_ERROR_INVALID_ATR;
52                if (TDi & 0x10)
53                        info->TA[m] = atr[n++];
54                if (TDi & 0x20)
55                        info->TB[m] = atr[n++];
56                if (TDi & 0x40)
57                        info->TC[m] = atr[n++];
58                if (!(TDi & 0x80)) {
59                        /* If the ATR indicates we support anything
60                         * in addition to T=0, there'll be a TCK byte
61                         * at the end of the string.
62                         * For now, simply chop it off. Later we may
63                         * want to verify it.
64                         */
65                        if (info->supported_protocols & ~0x1)
66                                len--;
67                        if (n < len)
68                                return IFD_ERROR_INVALID_ATR;
69                        break;
70                }
71                n++;
72        }
73
74        /* ATR didn't list any supported protocols, so
75         * we default to T=0 */
76        if (info->supported_protocols == 0) {
77                info->supported_protocols = 0x01;
78                info->default_protocol = IFD_PROTOCOL_T0;
79        }
80
81        ifd_debug(1, "supported protocols=0x%x, default protocol=%d",
82                  info->supported_protocols, info->default_protocol);
83        return 0;
84}
85
86/*
87 * Given the ATR info and a selected protocol, build the PTS
88 * string.
89 */
90int ifd_build_pts(const ifd_atr_info_t * info, int protocol, unsigned char *buf,
91                  size_t len)
92{
93        unsigned char ptsbuf[7], pck;
94        size_t n, ptslen = 0;
95
96        /* IFD_PROTOCOL_Tn is just n, so we take it easy here */
97        if (!(info->supported_protocols & (1 << protocol))) {
98                ct_error("Protocol not supported by card (according to ATR)");
99                return IFD_ERROR_NOT_SUPPORTED;
100        }
101
102        ptsbuf[ptslen++] = 0xFF;
103        ptsbuf[ptslen++] = protocol;
104        if (info->TA[0] != -1) {
105                ptsbuf[ptslen++] = info->TA[0];
106                ptsbuf[1] |= 0x10;
107        }
108        if (info->TC[0] == 255) {
109                ptsbuf[ptslen++] = 1;
110                ptsbuf[1] |= 0x20;
111        }
112
113        for (n = 0, pck = 0; n < ptslen; n++)
114                pck ^= ptsbuf[n];
115        ptsbuf[ptslen++] = pck;
116
117        if (ptslen > len)
118                return IFD_ERROR_BUFFER_TOO_SMALL;
119
120        memcpy(buf, ptsbuf, ptslen);
121        return ptslen;
122}
123
124/* validate a PTS response according to ISO7816-3 */
125int
126ifd_verify_pts(ifd_atr_info_t * info,
127               int protocol, const unsigned char *buf, size_t len)
128{
129        int n, i;
130        int ptsr[3];
131        int pck;
132
133        if (len < 3)
134                return IFD_ERROR_BUFFER_TOO_SMALL;
135
136        if (buf[0] != 0xFF)
137                return IFD_ERROR_INCOMPATIBLE_DEVICE;   /* not a pts response */
138
139        for (n = 0, pck = 0; n < len; n++)
140                pck ^= buf[n];
141
142        if (pck)
143                return IFD_ERROR_COMM_ERROR;
144        for (i = 0; i < 3; i++)
145                ptsr[i] = -1;
146        for (i = 0, n = 2; i < 3 && n < len - 1; i++) {
147                if (buf[1] & 1 << (i + 4))
148                        ptsr[i] = buf[n++];
149        }
150        if (n < len - 1)        /* extra bytes in response */
151                return IFD_ERROR_INCOMPATIBLE_DEVICE;
152        if (info->TA[0] != -1 && ptsr[0] != info->TA[0])
153                info->TA[0] = -1;
154        if (info->TC[0] == 255 && (ptsr[1] == -1 || (ptsr[1] & 1) == 0))
155                return IFD_ERROR_INCOMPATIBLE_DEVICE;
156        return 0;
157}
158
159int ifd_pts_complete(const unsigned char *pts, size_t len)
160{
161        unsigned int j = 2;
162
163        if (j > len)
164                return 0;
165        j = +ifd_count_bits(pts[1] & 0x70);
166        j++;
167        if (j > len)
168                return 0;
169        return 1;
170}
Note: See TracBrowser for help on using the repository browser.