Package smartcard :: Module ATR
[hide private]
[frames] | no frames]

Source Code for Module smartcard.ATR

  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   
30 -class ATR(object):
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
40 - def __init__(self, bytes):
41 """Construct a new atr from bytes.""" 42 self.bytes = bytes 43 self.__initInstance__()
44
45 - def __checksyncbyte__(self):
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
50 - def __initInstance__(self):
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 # initial character 72 self.TS = self.bytes[0] 73 74 # format character 75 self.T0 = self.bytes[1] 76 77 # count of historical bytes 78 self.K = self.T0 & 0x0f 79 80 # initialize optional characters lists 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 # historical bytes 136 self.historicalBytes = self.bytes[offset + 1:offset + 1 + self.K] 137 138 # checksum 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 # clock-rate conversion factor 150 if self.hasTA[0]: 151 self.FI = self.TA[0] >> 4 & 0x0f 152 else: 153 self.FI = None 154 155 # bit-rate adjustment factor 156 if self.hasTA[0]: 157 self.DI = self.TA[0] & 0x0f 158 else: 159 self.DI = None 160 161 # maximum programming current factor 162 if self.hasTB[0]: 163 self.II = self.TB[0] >> 5 & 0x03 164 else: 165 self.II = None 166 167 # programming voltage factor 168 if self.hasTB[0]: 169 self.PI1 = self.TB[0] & 0x1f 170 else: 171 self.PI1 = None 172 173 # extra guard time 174 self.N = self.TC[0]
175
176 - def getChecksum(self):
177 """Return the checksum of the ATR. Checksum is mandatory only 178 for T=1.""" 179 return self.TCK
180
181 - def getHistoricalBytes(self):
182 """Return historical bytes.""" 183 return self.historicalBytes
184
185 - def getHistoricalBytesCount(self):
186 """Return count of historical bytes.""" 187 return len(self.historicalBytes)
188
189 - def getInterfaceBytesCount(self):
190 """Return count of interface bytes.""" 191 return self.interfaceBytesCount
192
193 - def getTA1(self):
194 """Return TA1 byte.""" 195 return self.TA[0]
196
197 - def getTB1(self):
198 """Return TB1 byte.""" 199 return self.TB[0]
200
201 - def getTC1(self):
202 """Return TC1 byte.""" 203 return self.TC[0]
204
205 - def getTD1(self):
206 """Return TD1 byte.""" 207 return self.TD[0]
208
209 - def getBitRateFactor(self):
210 """Return bit rate factor.""" 211 if self.DI is not None: 212 return ATR.bitratefactor[self.DI] 213 else: 214 return 1
215
216 - def getClockRateConversion(self):
217 """Return clock rate conversion.""" 218 if self.FI is not None: 219 return ATR.clockrateconversion[self.FI] 220 else: 221 return 372
222
223 - def getProgrammingCurrent(self):
224 """Return maximum programming current.""" 225 if self.II is not None: 226 return ATR.currenttable[self.II] 227 else: 228 return 50
229
230 - def getProgrammingVoltage(self):
231 """Return programming voltage.""" 232 if self.PI1 is not None: 233 return 5 * (1 + self.PI1) 234 else: 235 return 5
236
237 - def getGuardTime(self):
238 """Return extra guard time.""" 239 return self.N
240
241 - def getSupportedProtocols(self):
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
252 - def isT0Supported(self):
253 """Return True if T=0 is supported.""" 254 protocols = self.getSupportedProtocols() 255 return 'T=0' in protocols
256
257 - def isT1Supported(self):
258 """Return True if T=1 is supported.""" 259 protocols = self.getSupportedProtocols() 260 return 'T=1' in protocols
261
262 - def isT15Supported(self):
263 """Return True if T=15 is supported.""" 264 protocols = self.getSupportedProtocols() 265 return 'T=15' in protocols
266
267 - def dump(self):
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
300 - def __str__(self):
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