This file is indexed.

/usr/lib/python3/dist-packages/smartcard/ATR.py is in python3-pyscard 1.9.4-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
"""ATR class managing some of the Answer To Reset content.

__author__ = "http://www.gemalto.com"

Copyright 2001-2012 gemalto
Author: Jean-Daniel Aussel, mailto:jean-daniel.aussel@gemalto.com

This file is part of pyscard.

pyscard is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

pyscard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with pyscard; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
"""

from __future__ import print_function
from smartcard.Exceptions import SmartcardException
from smartcard.util import toHexString


class ATR(object):
    """ATR class."""

    clockrateconversion = [372, 372, 558, 744, 1116, 1488, 1860, 'RFU',
                           'RFU', 512, 768, 1024, 1536, 2048, 'RFU', 'RFU',
                           'RFU']
    bitratefactor = ['RFU', 1, 2, 4, 8, 16, 32, 'RFU', 12, 20, 'RFU',
                     'RFU', 'RFU', 'RFU', 'RFU', 'RFU']
    currenttable = [25, 50, 100, 'RFU']

    def __init__(self, bytes):
        """Construct a new atr from bytes."""
        self.bytes = bytes
        self.__initInstance__()

    def __checksyncbyte__(self):
        """Check validity of TS."""
        if not 0x3b == self.bytes[0] and not 0x03f == self.bytes[0]:
            raise SmartcardException("invalid TS 0x%-0.2x" % self.bytes[0])

    def __initInstance__(self):
        """Parse ATR and initialize members:
            TS: initial character
            T0: format character
            TA[n], TB[n], TC[n], TD[n], for n=0,1,...: protocol parameters
                note: protocol parameters indices start at 0, e.g.
                TA[0], TA[1] correspond to the ISO standard TA1, TA2
                parameters
            historicalBytes: the ATR T1, T2, ..., TK historical bytes
            TCK: checksum byte (only for protocols different from T=0)
            FI: clock rate conversion factor
            DI: voltage adjustment factor
            PI1: programming voltage factor
            II: maximum programming current factor
            N: extra guard time
        """
        self.__checksyncbyte__()

        # initial character
        self.TS = self.bytes[0]

        # format character
        self.T0 = self.bytes[1]

        # count of historical bytes
        self.K = self.T0 & 0x0f

        # initialize optional characters lists
        self.TA = []
        self.TB = []
        self.TC = []
        self.TD = []
        self.Y = []
        self.hasTA = []
        self.hasTB = []
        self.hasTC = []
        self.hasTD = []

        TD = self.T0
        hasTD = 1
        n = 0
        offset = 1
        self.interfaceBytesCount = 0
        while hasTD:
            self.Y += [TD >> 4 & 0x0f]

            self.hasTD += [(self.Y[n] & 0x08) != 0]
            self.hasTC += [(self.Y[n] & 0x04) != 0]
            self.hasTB += [(self.Y[n] & 0x02) != 0]
            self.hasTA += [(self.Y[n] & 0x01) != 0]

            self.TA += [None]
            self.TB += [None]
            self.TC += [None]
            self.TD += [None]

            if self.hasTA[n]:
                self.TA[n] = self.bytes[offset + self.hasTA[n]]
            if self.hasTB[n]:
                self.TB[n] = self.bytes[offset + self.hasTA[n] + self.hasTB[n]]
            if self.hasTC[n]:
                self.TC[n] = self.bytes[offset +
                                        self.hasTA[n] +
                                        self.hasTB[n] +
                                        self.hasTC[n]]
            if self.hasTD[n]:
                self.TD[n] = self.bytes[offset +
                                        self.hasTA[n] +
                                        self.hasTB[n] +
                                        self.hasTC[n] +
                                        self.hasTD[n]]

            self.interfaceBytesCount += self.hasTA[n] +\
                self.hasTB[n] +\
                self.hasTC[n] +\
                self.hasTD[n]
            TD = self.TD[n]
            hasTD = self.hasTD[n]
            offset = offset + self.hasTA[n] + self.hasTB[n] +\
                self.hasTC[n] + self.hasTD[n]
            n = n + 1

        # historical bytes
        self.historicalBytes = self.bytes[offset + 1:offset + 1 + self.K]

        # checksum
        self.hasChecksum = (len(self.bytes) == offset + 1 + self.K + 1)
        if self.hasChecksum:
            self.TCK = self.bytes[-1]
            checksum = 0
            for b in self.bytes[1:]:
                checksum = checksum ^ b
            self.checksumOK = (checksum == 0)
        else:
            self.TCK = None

        # clock-rate conversion factor
        if self.hasTA[0]:
            self.FI = self.TA[0] >> 4 & 0x0f
        else:
            self.FI = None

        # bit-rate adjustment factor
        if self.hasTA[0]:
            self.DI = self.TA[0] & 0x0f
        else:
            self.DI = None

        # maximum programming current factor
        if self.hasTB[0]:
            self.II = self.TB[0] >> 5 & 0x03
        else:
            self.II = None

        # programming voltage factor
        if self.hasTB[0]:
            self.PI1 = self.TB[0] & 0x1f
        else:
            self.PI1 = None

        # extra guard time
        self.N = self.TC[0]

    def getChecksum(self):
        """Return the checksum of the ATR. Checksum is mandatory only
        for T=1."""
        return self.TCK

    def getHistoricalBytes(self):
        """Return historical bytes."""
        return self.historicalBytes

    def getHistoricalBytesCount(self):
        """Return count of historical bytes."""
        return len(self.historicalBytes)

    def getInterfaceBytesCount(self):
        """Return count of interface bytes."""
        return self.interfaceBytesCount

    def getTA1(self):
        """Return TA1 byte."""
        return self.TA[0]

    def getTB1(self):
        """Return TB1 byte."""
        return self.TB[0]

    def getTC1(self):
        """Return TC1 byte."""
        return self.TC[0]

    def getTD1(self):
        """Return TD1 byte."""
        return self.TD[0]

    def getBitRateFactor(self):
        """Return bit rate factor."""
        if self.DI is not None:
            return ATR.bitratefactor[self.DI]
        else:
            return 1

    def getClockRateConversion(self):
        """Return clock rate conversion."""
        if self.FI is not None:
            return ATR.clockrateconversion[self.FI]
        else:
            return 372

    def getProgrammingCurrent(self):
        """Return maximum programming current."""
        if self.II is not None:
            return ATR.currenttable[self.II]
        else:
            return 50

    def getProgrammingVoltage(self):
        """Return programming voltage."""
        if self.PI1 is not None:
            return 5 * (1 + self.PI1)
        else:
            return 5

    def getGuardTime(self):
        """Return extra guard time."""
        return self.N

    def getSupportedProtocols(self):
        """Returns a dictionnary of supported protocols."""
        protocols = {}
        for td in self.TD:
            if td is not None:
                strprotocol = "T=%d" % (td & 0x0F)
                protocols[strprotocol] = True
        if not self.hasTD[0]:
            protocols['T=0'] = True
        return protocols

    def isT0Supported(self):
        """Return True if T=0 is supported."""
        protocols = self.getSupportedProtocols()
        return 'T=0' in protocols

    def isT1Supported(self):
        """Return True if T=1 is supported."""
        protocols = self.getSupportedProtocols()
        return 'T=1' in protocols

    def isT15Supported(self):
        """Return True if T=15 is supported."""
        protocols = self.getSupportedProtocols()
        return 'T=15' in protocols

    def dump(self):
        """Dump the details of an ATR."""

        for i in range(0, len(self.TA)):
            if self.TA[i] is not None:
                print("TA%d: %x" % (i + 1, self.TA[i]))
            if self.TB[i] is not None:
                print("TB%d: %x" % (i + 1, self.TB[i]))
            if self.TC[i] is not None:
                print("TC%d: %x" % (i + 1, self.TC[i]))
            if self.TD[i] is not None:
                print("TD%d: %x" % (i + 1, self.TD[i]))

        print('supported protocols ' + ','.join(self.getSupportedProtocols()))
        print('T=0 supported: ' + str(self.isT0Supported()))
        print('T=1 supported: ' + str(self.isT1Supported()))

        if self.getChecksum():
            print('checksum: %d' % self.getChecksum())

        print('\tclock rate conversion factor: ' +
              str(self.getClockRateConversion()))
        print('\tbit rate adjustment factor: ' + str(self.getBitRateFactor()))

        print('\tmaximum programming current: ' +
              str(self.getProgrammingCurrent()))
        print('\tprogramming voltage: ' + str(self.getProgrammingVoltage()))

        print('\tguard time: ' + str(self.getGuardTime()))

        print('nb of interface bytes: %d' % self.getInterfaceBytesCount())
        print('nb of historical bytes: %d' % self.getHistoricalBytesCount())

    def __str__(self):
        """Returns a string representation of the ATR as a strem of bytes."""
        return toHexString(self.bytes)


if __name__ == '__main__':
    """Small sample illustrating the use of ATR."""

    atrs = [[0x3F, 0x65, 0x25, 0x00, 0x2C, 0x09, 0x69, 0x90, 0x00],
            [0x3F, 0x65, 0x25, 0x08, 0x93, 0x04, 0x6C, 0x90, 0x00],
            [0x3B, 0x16, 0x94, 0x7C, 0x03, 0x01, 0x00, 0x00, 0x0D],
            [0x3B, 0x65, 0x00, 0x00, 0x9C, 0x11, 0x01, 0x01, 0x03],
            [0x3B, 0xE3, 0x00, 0xFF, 0x81, 0x31, 0x52, 0x45, 0xA1,
             0xA2, 0xA3, 0x1B],
            [0x3B, 0xE5, 0x00, 0x00, 0x81, 0x21, 0x45, 0x9C, 0x10,
             0x01, 0x00, 0x80, 0x0D]]

    for atr in atrs:
        a = ATR(atr)
        print(80 * '-')
        print(a)
        a.dump()
        print(toHexString(a.getHistoricalBytes()))