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-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   
28 -class ATR:
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
37 - def __init__(self, bytes):
38 """Construct a new atr from bytes.""" 39 self.bytes = bytes 40 self.__initInstance__()
41
42 - def __checksyncbyte__(self):
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
47 - def __initInstance__(self):
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 # initial character 66 self.TS = self.bytes[0] 67 68 # format character 69 self.T0 = self.bytes[1] 70 71 # count of historical bytes 72 self.K = self.T0 & 0x0f 73 74 # initialize optional characters lists 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 # historical bytes 119 self.historicalBytes = self.bytes[offset + 1:offset + 1 + self.K] 120 121 # checksum 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 # clock-rate conversion factor 133 if self.hasTA[0]: 134 self.FI = self.TA[0] >> 4 & 0x0f 135 else: 136 self.FI = None 137 138 # bit-rate adjustment factor 139 if self.hasTA[0]: 140 self.DI = self.TA[0] & 0x0f 141 else: 142 self.DI = None 143 144 # maximum programming current factor 145 if self.hasTB[0]: 146 self.II = self.TB[0] >> 5 & 0x03 147 else: 148 self.II = None 149 150 # programming voltage factor 151 if self.hasTB[0]: 152 self.PI1 = self.TB[0] & 0x1f 153 else: 154 self.PI1 = None 155 156 # extra guard time 157 self.N = self.TC[0]
158
159 - def getChecksum(self):
160 """Return the checksum of the ATR. Checksum is mandatory only 161 for T=1.""" 162 return self.TCK
163
164 - def getHistoricalBytes(self):
165 """Return historical bytes.""" 166 return self.historicalBytes
167
168 - def getHistoricalBytesCount(self):
169 """Return count of historical bytes.""" 170 return len(self.historicalBytes)
171
172 - def getInterfaceBytesCount(self):
173 """Return count of interface bytes.""" 174 return self.interfaceBytesCount
175
176 - def getTA1(self):
177 """Return TA1 byte.""" 178 return self.TA[0]
179
180 - def getTB1(self):
181 """Return TB1 byte.""" 182 return self.TB[0]
183
184 - def getTC1(self):
185 """Return TC1 byte.""" 186 return self.TC[0]
187
188 - def getTD1(self):
189 """Return TD1 byte.""" 190 return self.TD[0]
191
192 - def getBitRateFactor(self):
193 """Return bit rate factor.""" 194 if self.DI != None: 195 return ATR.bitratefactor[self.DI] 196 else: 197 return 1
198
199 - def getClockRateConversion(self):
200 """Return clock rate conversion.""" 201 if self.FI != None: 202 return ATR.clockrateconversion[self.FI] 203 else: 204 return 372
205
206 - def getProgrammingCurrent(self):
207 """Return maximum programming current.""" 208 if self.II != None: 209 return ATR.currenttable[self.II] 210 else: 211 return 50
212
213 - def getProgrammingVoltage(self):
214 """Return programming voltage.""" 215 if self.PI1 != None: 216 return 5 * (1 + self.PI1) 217 else: 218 return 5
219
220 - def getGuardTime(self):
221 """Return extra guard time.""" 222 return self.N
223
224 - def getSupportedProtocols(self):
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
235 - def isT0Supported(self):
236 """Return True if T=0 is supported.""" 237 protocols = self.getSupportedProtocols() 238 return protocols.has_key('T=0')
239
240 - def isT1Supported(self):
241 """Return True if T=1 is supported.""" 242 protocols = self.getSupportedProtocols() 243 return protocols.has_key('T=1')
244
245 - def isT15Supported(self):
246 """Return True if T=15 is supported.""" 247 protocols = self.getSupportedProtocols() 248 return protocols.has_key('T=15')
249
250 - def dump(self):
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
280 - def __str__(self):
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