Skip to content

Commit 790a8fb

Browse files
committed
enhance logging and AID selection
1 parent dc177e9 commit 790a8fb

File tree

1 file changed

+75
-54
lines changed

1 file changed

+75
-54
lines changed

card/ICC.py

Lines changed: 75 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class ISO7816(object):
5757
standard file tags available in "file_tags" class attribute dictionnary
5858
"""
5959

60-
dbg = 0
60+
dbg = 1
6161

6262
INS_dic = {
6363
0x04 : 'DEACTIVATE FILE',
@@ -193,7 +193,7 @@ def ATR_scan(self, smlist_file="/usr/share/pcsc/smartcard_list.txt"):
193193
% toHexString(ATR(self.ATR).getHistoricalBytes()))
194194
ATRcs = ATR(self.ATR).getChecksum()
195195
if ATRcs :
196-
print('checksum: 0x%X' % ATRcs)
196+
print('checksum: 0x%.2X' % ATRcs)
197197
else:
198198
print('no ATR checksum')
199199
print('\nusing pcsc_scan ATR list file: %s' % smlist_file)
@@ -712,16 +712,16 @@ def parse_file(self, Data=[]):
712712
parse_file(self, Data) -> Dict()
713713
714714
parses a list of bytes returned when selecting a file
715-
interprets the content of some informative bytes
716-
for file structure and parsing method...
715+
interprets the content of some informative bytes for file structure and
716+
decoding method...
717717
"""
718718
ber = BERTLV_parser( Data )
719719
if self.dbg >= 2:
720-
log(3, '(parse_file) BER structure:\n%s' % ber)
721-
if len(ber) > 1 and self.dbg:
720+
log(3, '(parse_file) BER structure:\n%r' % ber)
721+
if self.dbg and len(ber) > 1:
722722
# TODO: implements recursive BER object parsing
723-
log(1, '(parse_file) contain more than 1 BER object: '\
724-
'%s\nnot implemented' % ber)
723+
log(2, '(parse_file) contain more than 1 BER object: %r : not implemented'\
724+
% ber)
725725

726726
# for FCP control structure, precise parsing is done
727727
# this structure seems to be the most used for (U)SIM cards
@@ -741,14 +741,12 @@ def parse_file(self, Data=[]):
741741
fil = {}
742742
if ber[0][0][2] == 0x4:
743743
fil['Control'] = 'FMD'
744-
if self.dbg:
745-
log(1, '(parse_file) FMD file structure parsing '\
746-
'not implemented')
744+
if self.dbg >= 2:
745+
log(2, '(parse_file) FMD file structure parsing not implemented')
747746
elif ber[0][0][2] == 0xF:
748747
fil['Control'] = 'FCI'
749-
if self.dbg:
750-
log(1, '(parse_file) FCI 0xF file structure parsing '\
751-
'not implemented')
748+
if self.dbg >= 2:
749+
log(2, '(parse_file) FCI 0xF file structure parsing not implemented')
752750
else:
753751
fil['Control'] = ber[0][0]
754752
if self.dbg:
@@ -762,8 +760,8 @@ def parse_FCP(self, Data=[]):
762760
parse_FCP(Data) -> Dict()
763761
764762
parses a list of bytes returned when selecting a file
765-
interprets the content of some informative bytes
766-
for file structure and parsing method...
763+
interprets the content of some informative bytes for file structure and
764+
decoding method...
767765
"""
768766
fil = {}
769767
# loop on the Data bytes to parse TLV'style attributes
@@ -799,7 +797,7 @@ def parse_FCP(self, Data=[]):
799797
fil[self.file_tags[T]] = V
800798
if self.dbg >= 2:
801799
log(3, '(parse_FCP) parse_security_attribute not implemented '\
802-
'for tag 0x%X' % T)
800+
'for tag 0x%.2X' % T)
803801
self.parse_security_attribute(V, fil)
804802
# file size or length
805803
elif T in (0x80, 0x81):
@@ -1097,7 +1095,7 @@ def parse_FCI(self, Data=[]):
10971095
fil[self.file_tags[T]] = V
10981096
if self.dbg >= 2:
10991097
log(3, '(parse_FCI) parse_security_attribute not implemented '\
1100-
'for tag 0x%X' % T)
1098+
'for tag 0x%.2X' % T)
11011099
self.parse_security_attribute(V, fil)
11021100
# file size or length
11031101
elif T in (0x80, 0x81):
@@ -1578,7 +1576,7 @@ def __init__(self, reader=''):
15781576
initialized on the MF
15791577
"""
15801578
ISO7816.__init__(self, CLA=0x00, reader=reader)
1581-
self.AID = []
1579+
self.AID = []
15821580
self.AID_GP = {}
15831581
#
15841582
if self.dbg >= 2:
@@ -1658,15 +1656,16 @@ def parse_pin_status(Data, fil):
16581656
fil['PIN Status'] = PIN_status
16591657
return fil
16601658

1661-
def get_AID(self):
1659+
def get_AID(self, backtoMF=False):
16621660
"""
16631661
checks EF_DIR at the MF level,
16641662
and available AID (Application ID) referenced
16651663
16661664
puts it into self.AID
16671665
"""
1668-
#go back to MF and select EF_DIR
1669-
#self.select(addr=[])
1666+
# go back to MF and select EF_DIR
1667+
if backtoMF:
1668+
self.select(addr=[])
16701669

16711670
# EF_DIR is at the MF level and contains Application ID:
16721671
EF_DIR = self.select([0x2F, 0x00], type='pmf')
@@ -1681,9 +1680,20 @@ def get_AID(self):
16811680
if (rec[0], rec[2]) == (0x61, 0x4F) and len(rec) > 6 \
16821681
and rec[4:4+rec[3]] not in self.AID:
16831682
self.AID.append( rec[4:4+rec[3]] )
1683+
1684+
def get_AID_GP(self):
1685+
"""
1686+
tries to select all AID addresses from AID_GP_app_code at the MF level
16841687
1685-
#for aid in self.AID:
1686-
# self.interpret_AID(aid)
1688+
puts those to which there is a positive SW response into self.AID_GP
1689+
"""
1690+
for aid in self.AID_GP_code.keys():
1691+
aid = list(aid)
1692+
self.select_by_name(aid)
1693+
if self.coms()[2] == (0x90, 0x00):
1694+
# positive response, where we could read the data returned by
1695+
# the application
1696+
self.AID_GP[tuple(aid)] = BERTLV_extract(self.coms()[3])
16871697

16881698
@staticmethod
16891699
def interpret_AID(aid=[]):
@@ -1692,47 +1702,58 @@ def interpret_AID(aid=[]):
16921702
"""
16931703
if len(aid) < 11:
16941704
return
1695-
# check AID format
1696-
aid_rid = tuple(aid[0:5])
1697-
aid_app = tuple(aid[5:7])
1698-
aid_country = tuple(aid[7:9])
1699-
aid_provider = tuple(aid[9:11])
1705+
aid = tuple(aid)
1706+
aid_rid, aid_app, aid_country = aid[0:5], aid[5:7], aid[7:9]
1707+
aid = {
1708+
'rid' : '%.2X %.2X %.2X %.2X %.2X' % aid_rid,
1709+
'app' : '%.2X %.2X' % aid_app,
1710+
'country' : '%.2X %.2X' % aid_country,
1711+
'provider' : '%.2X %.2X' % aid[9:11],
1712+
'prop' : ('%.2X ' * len(aid[11:])) % aid[11:]
1713+
}
17001714

1701-
# get AID application code, depending on SDO...
1715+
# check for known AID format
1716+
if aid_rid in UICC.AID_RID.keys():
1717+
aid['rid'] += ' (%s)' % UICC.AID_RID[aid_rid]
17021718
if aid_rid == (0xA0, 0x00, 0x00, 0x00, 0x09) \
17031719
and aid_app in UICC.AID_ETSI_app_code.keys():
1704-
aid_app = UICC.AID_ETSI_app_code[aid_app]
1705-
if aid_rid == (0xA0, 0x00, 0x00, 0x00, 0x87) \
1720+
aid['app'] += ' (%s)' % UICC.AID_ETSI_app_code[aid_app]
1721+
elif aid_rid == (0xA0, 0x00, 0x00, 0x00, 0x87) \
17061722
and aid_app in UICC.AID_3GPP_app_code.keys():
1707-
aid_app = UICC.AID_3GPP_app_code[aid_app]
1708-
if aid_rid == (0xA0, 0x00, 0x00, 0x03, 0x43) \
1723+
aid['app'] += ' (%s)' % UICC.AID_3GPP_app_code[aid_app]
1724+
elif aid_rid == (0xA0, 0x00, 0x00, 0x03, 0x43) \
17091725
and aid_app in UICC.AID_3GPP2_app_code.keys():
1710-
aid_app = UICC.AID_3GPP2_app_code[aid_app]
1711-
if aid_rid == (0xA0, 0x00, 0x00, 0x06, 0x45) \
1726+
aid['app'] += ' (%s)' % UICC.AID_3GPP2_app_code[aid_app]
1727+
elif aid_rid == (0xA0, 0x00, 0x00, 0x06, 0x45) \
17121728
and aid_app in UICC.AID_OneM2M_app_code.keys():
1713-
aid_app = UICC.AID_OneM2M_app_code[aid_app]
1714-
# get AID responsible SDO and country
1715-
if aid_rid in UICC.AID_RID.keys():
1716-
aid_rid = UICC.AID_RID[aid_rid]
1729+
aid['app'] += ' (%s)' % UICC.AID_OneM2M_app_code[aid_app]
17171730
if aid_country in UICC.AID_country_code.keys():
17181731
aid_country = UICC.AID_country_code[aid_country]
1719-
1720-
return('%s || %s || %s || %s || %s' \
1721-
% (aid_rid, aid_app, aid_country, aid_provider, tuple(aid[11:])))
1732+
#
1733+
return 'rid %(rid)s || app %(app)s || country %(country)s || '\
1734+
'provider %(provider)s || %(prop)s' % aid
17221735

1723-
def get_AID_GP(self):
1736+
@staticmethod
1737+
def interpret_AID_GP(aid=[]):
17241738
"""
1725-
tries to select all AID addresses from AID_GP_app_code at the MF level
1726-
1727-
puts those to which there is a positive SW response into self.AID_GP
1739+
returns a string with the interpretation of the GlobalPlatform AID provided
17281740
"""
1729-
for aid in self.AID_GP_code.keys():
1730-
aid = list(aid)
1731-
self.select_by_name(aid)
1732-
if self.coms()[2] == (0x90, 0x00):
1733-
# positive response, where we could read the data returned by
1734-
# the application
1735-
self.AID_GP[tuple(aid)] = BERTLV_extract(self.coms()[3])
1741+
for code, interp in UICC.AID_GP_code.items():
1742+
if code == aid[:len(code)]:
1743+
if len(aid) > len(code):
1744+
fstr = 'GP || ' + '%.2X ' * len(code) + '(' + interp + ')' + ' || ' + '%.2X ' * (len(aid)-len(code))
1745+
return fstr % tuple(code + aid[len(code):])
1746+
else:
1747+
fstr = 'GP || ' + '%.2X ' * len(code) + '(' + interp + ')'
1748+
return fstr % code
1749+
1750+
def print_AID(self):
1751+
self.get_AID()
1752+
for aid in self.AID:
1753+
print(self.interpret_AID(aid))
1754+
self.get_AID_GP()
1755+
for aid in self.AID_GP:
1756+
print(self.interpret_AID_GP(aid))
17361757

17371758
def get_ICCID(self):
17381759
"""

0 commit comments

Comments
 (0)