1 """ATR class managing some of the Answer To Reset content.
2
3 __author__ = "http://www.gemalto.com"
4
5 Copyright 2001-2011 gemalto
6 Author: Jean-Daniel Aussel, mailto:jean-daniel.aussel@gemalto.com
7
8 This file is part of pyscard.
9
10 pyscard is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14
15 pyscard is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public License
21 along with pyscard; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 """
24
25 from smartcard.Exceptions import SmartcardException
26
27
29 """ATR class."""
30
31 clockrateconversion = [372, 372, 558, 744, 1116, 1488, 1860, 'RFU',
32 'RFU', 512, 768, 1024, 1536, 2048, 'RFU', 'RFU', 'RFU']
33 bitratefactor = ['RFU', 1, 2, 4, 8, 16, 32, 'RFU', 12, 20, 'RFU',
34 'RFU', 'RFU', 'RFU', 'RFU', 'RFU']
35 currenttable = [25, 50, 100, 'RFU']
36
38 """Construct a new atr from bytes."""
39 self.bytes = bytes
40 self.__initInstance__()
41
43 """Check validity of TS."""
44 if not 0x3b == self.bytes[0] and not 0x03f == self.bytes[0]:
45 raise SmartcardException("invalid TS 0x%-0.2x" % self.bytes[0])
46
48 """Parse ATR and initialize members:
49 TS: initial character
50 T0: format character
51 TA[n], TB[n], TC[n], TD[n], for n=0,1,...: protocol parameters
52 note: protocol parameters indices start at 0, e.g.
53 TA[0], TA[1] correspond to the ISO standard TA1, TA2
54 parameters
55 historicalBytes: the ATR T1, T2, ..., TK historical bytes
56 TCK: checksum byte (only for protocols different from T=0)
57 FI: clock rate conversion factor
58 DI: voltage adjustment factor
59 PI1: programming voltage factor
60 II: maximum programming current factor
61 N: extra guard time
62 """
63 self.__checksyncbyte__()
64
65
66 self.TS = self.bytes[0]
67
68
69 self.T0 = self.bytes[1]
70
71
72 self.K = self.T0 & 0x0f
73
74
75 self.TA = []
76 self.TB = []
77 self.TC = []
78 self.TD = []
79 self.Y = []
80 self.hasTA = []
81 self.hasTB = []
82 self.hasTC = []
83 self.hasTD = []
84
85 TD = self.T0
86 hasTD = 1
87 n = 0
88 offset = 1
89 self.interfaceBytesCount = 0
90 while hasTD:
91 self.Y += [TD >> 4 & 0x0f]
92
93 self.hasTD += [(self.Y[n] & 0x08) != 0]
94 self.hasTC += [(self.Y[n] & 0x04) != 0]
95 self.hasTB += [(self.Y[n] & 0x02) != 0]
96 self.hasTA += [(self.Y[n] & 0x01) != 0]
97
98 self.TA += [None]
99 self.TB += [None]
100 self.TC += [None]
101 self.TD += [None]
102
103 if self.hasTA[n]:
104 self.TA[n] = self.bytes[offset + self.hasTA[n]]
105 if self.hasTB[n]:
106 self.TB[n] = self.bytes[offset + self.hasTA[n] + self.hasTB[n]]
107 if self.hasTC[n]:
108 self.TC[n] = self.bytes[offset + self.hasTA[n] + self.hasTB[n] + self.hasTC[n]]
109 if self.hasTD[n]:
110 self.TD[n] = self.bytes[offset + self.hasTA[n] + self.hasTB[n] + self.hasTC[n] + self.hasTD[n]]
111
112 self.interfaceBytesCount += self.hasTA[n] + self.hasTB[n] + self.hasTC[n] + self.hasTD[n]
113 TD = self.TD[n]
114 hasTD = self.hasTD[n]
115 offset = offset + self.hasTA[n] + self.hasTB[n] + self.hasTC[n] + self.hasTD[n]
116 n = n + 1
117
118
119 self.historicalBytes = self.bytes[offset + 1:offset + 1 + self.K]
120
121
122 self.hasChecksum = (len(self.bytes) == offset + 1 + self.K + 1)
123 if self.hasChecksum:
124 self.TCK = self.bytes[-1]
125 checksum = 0
126 for b in self.bytes[1:]:
127 checksum = checksum ^ b
128 self.checksumOK = (checksum == 0)
129 else:
130 self.TCK = None
131
132
133 if self.hasTA[0]:
134 self.FI = self.TA[0] >> 4 & 0x0f
135 else:
136 self.FI = None
137
138
139 if self.hasTA[0]:
140 self.DI = self.TA[0] & 0x0f
141 else:
142 self.DI = None
143
144
145 if self.hasTB[0]:
146 self.II = self.TB[0] >> 5 & 0x03
147 else:
148 self.II = None
149
150
151 if self.hasTB[0]:
152 self.PI1 = self.TB[0] & 0x1f
153 else:
154 self.PI1 = None
155
156
157 self.N = self.TC[0]
158
160 """Return the checksum of the ATR. Checksum is mandatory only
161 for T=1."""
162 return self.TCK
163
165 """Return historical bytes."""
166 return self.historicalBytes
167
169 """Return count of historical bytes."""
170 return len(self.historicalBytes)
171
173 """Return count of interface bytes."""
174 return self.interfaceBytesCount
175
177 """Return TA1 byte."""
178 return self.TA[0]
179
181 """Return TB1 byte."""
182 return self.TB[0]
183
185 """Return TC1 byte."""
186 return self.TC[0]
187
189 """Return TD1 byte."""
190 return self.TD[0]
191
193 """Return bit rate factor."""
194 if self.DI != None:
195 return ATR.bitratefactor[self.DI]
196 else:
197 return 1
198
200 """Return clock rate conversion."""
201 if self.FI != None:
202 return ATR.clockrateconversion[self.FI]
203 else:
204 return 372
205
207 """Return maximum programming current."""
208 if self.II != None:
209 return ATR.currenttable[self.II]
210 else:
211 return 50
212
214 """Return programming voltage."""
215 if self.PI1 != None:
216 return 5 * (1 + self.PI1)
217 else:
218 return 5
219
221 """Return extra guard time."""
222 return self.N
223
225 """Returns a dictionnary of supported protocols."""
226 protocols = {}
227 for td in self.TD:
228 if td != None:
229 strprotocol = "T=%d" % (td & 0x0F)
230 protocols[strprotocol] = True
231 if not self.hasTD[0]:
232 protocols['T=0'] = True
233 return protocols
234
236 """Return True if T=0 is supported."""
237 protocols = self.getSupportedProtocols()
238 return protocols.has_key('T=0')
239
241 """Return True if T=1 is supported."""
242 protocols = self.getSupportedProtocols()
243 return protocols.has_key('T=1')
244
246 """Return True if T=15 is supported."""
247 protocols = self.getSupportedProtocols()
248 return protocols.has_key('T=15')
249
251 """Dump the details of an ATR."""
252
253 for i in range(0, len(self.TA)):
254 if self.TA[i] != None:
255 print "TA%d: %x" % (i + 1, self.TA[i])
256 if self.TB[i] != None:
257 print "TB%d: %x" % (i + 1, self.TB[i])
258 if self.TC[i] != None:
259 print "TC%d: %x" % (i + 1, self.TC[i])
260 if self.TD[i] != None:
261 print "TD%d: %x" % (i + 1, self.TD[i])
262
263 print 'supported protocols', self.getSupportedProtocols()
264 print 'T=0 supported', self.isT0Supported()
265 print 'T=1 supported', self.isT1Supported()
266
267 print 'checksum:', self.getChecksum()
268
269 print '\tclock rate conversion factor:', self.getClockRateConversion()
270 print '\tbit rate adjustment factor:', self.getBitRateFactor()
271
272 print '\tmaximum programming current:', self.getProgrammingCurrent()
273 print '\tprogramming voltage:', self.getProgrammingVoltage()
274
275 print '\tguard time:', self.getGuardTime()
276
277 print 'nb of interface bytes:', self.getInterfaceBytesCount()
278 print 'nb of historical bytes:', self.getHistoricalBytesCount()
279
281 """Returns a string representation of the ATR as a strem of bytes."""
282 return reduce(lambda a, b: a + "%-0.2X " % ((b + 256) % 256), self.bytes, '')
283
284
285 if __name__ == '__main__':
286 """Small sample illustrating the use of ATR."""
287
288 atrs = [[0x3F, 0x65, 0x25, 0x00, 0x2C, 0x09, 0x69, 0x90, 0x00],
289 [0x3F, 0x65, 0x25, 0x08, 0x93, 0x04, 0x6C, 0x90, 0x00],
290 [0x3B, 0x16, 0x94, 0x7C, 0x03, 0x01, 0x00, 0x00, 0x0D],
291 [0x3B, 0x65, 0x00, 0x00, 0x9C, 0x11, 0x01, 0x01, 0x03],
292 [0x3B, 0xE3, 0x00, 0xFF, 0x81, 0x31, 0x52, 0x45, 0xA1,
293 0xA2, 0xA3, 0x1B],
294 [0x3B, 0xE5, 0x00, 0x00, 0x81, 0x21, 0x45, 0x9C, 0x10,
295 0x01, 0x00, 0x80, 0x0D]]
296
297 for atr in atrs:
298 a = ATR(atr)
299 print 80 * '-'
300 print a
301 a.dump()
302 print reduce(lambda a, b: a + "%-0.2X " % ((b + 256) % 256), a.getHistoricalBytes(), '')
303