1 """ATR class managing some of the Answer To Reset content.
2
3 __author__ = "http://www.gemalto.com"
4
5 Copyright 2001-2012 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 __future__ import print_function
26 from smartcard.Exceptions import SmartcardException
27 from smartcard.util import toHexString
28
29
31 """ATR class."""
32
33 clockrateconversion = [372, 372, 558, 744, 1116, 1488, 1860, 'RFU',
34 'RFU', 512, 768, 1024, 1536, 2048, 'RFU', 'RFU',
35 'RFU']
36 bitratefactor = ['RFU', 1, 2, 4, 8, 16, 32, 'RFU', 12, 20, 'RFU',
37 'RFU', 'RFU', 'RFU', 'RFU', 'RFU']
38 currenttable = [25, 50, 100, 'RFU']
39
41 """Construct a new atr from bytes."""
42 self.bytes = bytes
43 self.__initInstance__()
44
46 """Check validity of TS."""
47 if not 0x3b == self.bytes[0] and not 0x03f == self.bytes[0]:
48 raise SmartcardException("invalid TS 0x%-0.2x" % self.bytes[0])
49
51 """
52 Parse ATR and initialize members:
53 - TS: initial character
54 - T0: format character
55 - TA[n], TB[n], TC[n], TD[n], for n=0,1,...: protocol parameters
56
57 @note: protocol parameters indices start at 0, e.g.
58 TA[0], TA[1] correspond to the ISO standard TA1, TA2
59 parameters
60
61 - historicalBytes: the ATR T1, T2, ..., TK historical bytes
62 - TCK: checksum byte (only for protocols different from T=0)
63 - FI: clock rate conversion factor
64 - DI: voltage adjustment factor
65 - PI1: programming voltage factor
66 - II: maximum programming current factor
67 - N: extra guard time
68 """
69 self.__checksyncbyte__()
70
71
72 self.TS = self.bytes[0]
73
74
75 self.T0 = self.bytes[1]
76
77
78 self.K = self.T0 & 0x0f
79
80
81 self.TA = []
82 self.TB = []
83 self.TC = []
84 self.TD = []
85 self.Y = []
86 self.hasTA = []
87 self.hasTB = []
88 self.hasTC = []
89 self.hasTD = []
90
91 TD = self.T0
92 hasTD = 1
93 n = 0
94 offset = 1
95 self.interfaceBytesCount = 0
96 while hasTD:
97 self.Y += [TD >> 4 & 0x0f]
98
99 self.hasTD += [(self.Y[n] & 0x08) != 0]
100 self.hasTC += [(self.Y[n] & 0x04) != 0]
101 self.hasTB += [(self.Y[n] & 0x02) != 0]
102 self.hasTA += [(self.Y[n] & 0x01) != 0]
103
104 self.TA += [None]
105 self.TB += [None]
106 self.TC += [None]
107 self.TD += [None]
108
109 if self.hasTA[n]:
110 self.TA[n] = self.bytes[offset + self.hasTA[n]]
111 if self.hasTB[n]:
112 self.TB[n] = self.bytes[offset + self.hasTA[n] + self.hasTB[n]]
113 if self.hasTC[n]:
114 self.TC[n] = self.bytes[offset +
115 self.hasTA[n] +
116 self.hasTB[n] +
117 self.hasTC[n]]
118 if self.hasTD[n]:
119 self.TD[n] = self.bytes[offset +
120 self.hasTA[n] +
121 self.hasTB[n] +
122 self.hasTC[n] +
123 self.hasTD[n]]
124
125 self.interfaceBytesCount += self.hasTA[n] +\
126 self.hasTB[n] +\
127 self.hasTC[n] +\
128 self.hasTD[n]
129 TD = self.TD[n]
130 hasTD = self.hasTD[n]
131 offset = offset + self.hasTA[n] + self.hasTB[n] +\
132 self.hasTC[n] + self.hasTD[n]
133 n = n + 1
134
135
136 self.historicalBytes = self.bytes[offset + 1:offset + 1 + self.K]
137
138
139 self.hasChecksum = (len(self.bytes) == offset + 1 + self.K + 1)
140 if self.hasChecksum:
141 self.TCK = self.bytes[-1]
142 checksum = 0
143 for b in self.bytes[1:]:
144 checksum = checksum ^ b
145 self.checksumOK = (checksum == 0)
146 else:
147 self.TCK = None
148
149
150 if self.hasTA[0]:
151 self.FI = self.TA[0] >> 4 & 0x0f
152 else:
153 self.FI = None
154
155
156 if self.hasTA[0]:
157 self.DI = self.TA[0] & 0x0f
158 else:
159 self.DI = None
160
161
162 if self.hasTB[0]:
163 self.II = self.TB[0] >> 5 & 0x03
164 else:
165 self.II = None
166
167
168 if self.hasTB[0]:
169 self.PI1 = self.TB[0] & 0x1f
170 else:
171 self.PI1 = None
172
173
174 self.N = self.TC[0]
175
177 """Return the checksum of the ATR. Checksum is mandatory only
178 for T=1."""
179 return self.TCK
180
182 """Return historical bytes."""
183 return self.historicalBytes
184
186 """Return count of historical bytes."""
187 return len(self.historicalBytes)
188
190 """Return count of interface bytes."""
191 return self.interfaceBytesCount
192
194 """Return TA1 byte."""
195 return self.TA[0]
196
198 """Return TB1 byte."""
199 return self.TB[0]
200
202 """Return TC1 byte."""
203 return self.TC[0]
204
206 """Return TD1 byte."""
207 return self.TD[0]
208
210 """Return bit rate factor."""
211 if self.DI is not None:
212 return ATR.bitratefactor[self.DI]
213 else:
214 return 1
215
217 """Return clock rate conversion."""
218 if self.FI is not None:
219 return ATR.clockrateconversion[self.FI]
220 else:
221 return 372
222
224 """Return maximum programming current."""
225 if self.II is not None:
226 return ATR.currenttable[self.II]
227 else:
228 return 50
229
231 """Return programming voltage."""
232 if self.PI1 is not None:
233 return 5 * (1 + self.PI1)
234 else:
235 return 5
236
238 """Return extra guard time."""
239 return self.N
240
242 """Returns a dictionnary of supported protocols."""
243 protocols = {}
244 for td in self.TD:
245 if td is not None:
246 strprotocol = "T=%d" % (td & 0x0F)
247 protocols[strprotocol] = True
248 if not self.hasTD[0]:
249 protocols['T=0'] = True
250 return protocols
251
253 """Return True if T=0 is supported."""
254 protocols = self.getSupportedProtocols()
255 return 'T=0' in protocols
256
258 """Return True if T=1 is supported."""
259 protocols = self.getSupportedProtocols()
260 return 'T=1' in protocols
261
263 """Return True if T=15 is supported."""
264 protocols = self.getSupportedProtocols()
265 return 'T=15' in protocols
266
268 """Dump the details of an ATR."""
269
270 for i in range(0, len(self.TA)):
271 if self.TA[i] is not None:
272 print("TA%d: %x" % (i + 1, self.TA[i]))
273 if self.TB[i] is not None:
274 print("TB%d: %x" % (i + 1, self.TB[i]))
275 if self.TC[i] is not None:
276 print("TC%d: %x" % (i + 1, self.TC[i]))
277 if self.TD[i] is not None:
278 print("TD%d: %x" % (i + 1, self.TD[i]))
279
280 print('supported protocols ' + ','.join(self.getSupportedProtocols()))
281 print('T=0 supported: ' + str(self.isT0Supported()))
282 print('T=1 supported: ' + str(self.isT1Supported()))
283
284 if self.getChecksum():
285 print('checksum: %d' % self.getChecksum())
286
287 print('\tclock rate conversion factor: ' +
288 str(self.getClockRateConversion()))
289 print('\tbit rate adjustment factor: ' + str(self.getBitRateFactor()))
290
291 print('\tmaximum programming current: ' +
292 str(self.getProgrammingCurrent()))
293 print('\tprogramming voltage: ' + str(self.getProgrammingVoltage()))
294
295 print('\tguard time: ' + str(self.getGuardTime()))
296
297 print('nb of interface bytes: %d' % self.getInterfaceBytesCount())
298 print('nb of historical bytes: %d' % self.getHistoricalBytesCount())
299
301 """Returns a string representation of the ATR as a strem of bytes."""
302 return toHexString(self.bytes)
303
304
305 if __name__ == '__main__':
306 """Small sample illustrating the use of ATR."""
307
308 atrs = [[0x3F, 0x65, 0x25, 0x00, 0x2C, 0x09, 0x69, 0x90, 0x00],
309 [0x3F, 0x65, 0x25, 0x08, 0x93, 0x04, 0x6C, 0x90, 0x00],
310 [0x3B, 0x16, 0x94, 0x7C, 0x03, 0x01, 0x00, 0x00, 0x0D],
311 [0x3B, 0x65, 0x00, 0x00, 0x9C, 0x11, 0x01, 0x01, 0x03],
312 [0x3B, 0xE3, 0x00, 0xFF, 0x81, 0x31, 0x52, 0x45, 0xA1,
313 0xA2, 0xA3, 0x1B],
314 [0x3B, 0xE5, 0x00, 0x00, 0x81, 0x21, 0x45, 0x9C, 0x10,
315 0x01, 0x00, 0x80, 0x0D]]
316
317 for atr in atrs:
318 a = ATR(atr)
319 print(80 * '-')
320 print(a)
321 a.dump()
322 print(toHexString(a.getHistoricalBytes()))
323