Extend the GSM card module with lots of SIM card commands
including STATUS, TERMINAL PROFILE, TERMINAL RESPONSE, UPDATE BINARY,...
This commit is contained in:
parent
14819e9661
commit
8483d8a7ec
|
@ -1,32 +1,291 @@
|
||||||
import utils
|
import utils
|
||||||
from iso_card import *
|
from iso_card import *
|
||||||
|
import building_blocks
|
||||||
|
|
||||||
class GSM_Card(ISO_Card):
|
class GSM_Card(building_blocks.Card_with_read_binary,ISO_Card):
|
||||||
DRIVER_NAME = ["GSM"]
|
DRIVER_NAME = ["GSM"]
|
||||||
COMMAND_GET_RESPONSE = C_APDU("\xa0\xC0\x00\x00")
|
COMMAND_GET_RESPONSE = C_APDU("\xa0\xC0\x00\x00")
|
||||||
|
CLA = 0xA0
|
||||||
|
APDU_GET_RESPONSE = C_APDU(cla=CLA,ins=0xC0)
|
||||||
|
APDU_RUN_GSM_ALGO = C_APDU(cla=CLA,ins=0x88)
|
||||||
|
APDU_VERIFY_PIN = C_APDU(cla=CLA,ins=0x20)
|
||||||
|
|
||||||
|
APDU_SELECT_FILE = C_APDU(cla=CLA,ins=0xA4)
|
||||||
|
APDU_READ_BINARY = C_APDU(cla=CLA,ins=0xB0)
|
||||||
|
APDU_STATUS = C_APDU(cla=CLA,ins=0xF2)
|
||||||
|
APDU_UPD_BINARY = C_APDU(cla=CLA,ins=0xD6)
|
||||||
|
APDU_UPD_RECORD = C_APDU(cla=CLA,ins=0xDC)
|
||||||
|
|
||||||
|
# TS 11.14 / STK related
|
||||||
|
APDU_TERMINAL_PROFILE = C_APDU(cla=CLA,ins=0x10)
|
||||||
|
APDU_ENVELOPE = C_APDU(cla=CLA,ins=0xC2)
|
||||||
|
APDU_FETCH = C_APDU(cla=CLA,ins=0x12)
|
||||||
|
APDU_TERMINAL_RESPONSE = C_APDU(cla=CLA,ins=0x14)
|
||||||
|
|
||||||
STATUS_MAP = {
|
STATUS_MAP = {
|
||||||
Card.PURPOSE_GET_RESPONSE: ("9F??", )
|
Card.PURPOSE_GET_RESPONSE: ("9F??", )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INTERESTING_DFS = [
|
||||||
|
("DF.GSM", "\x7f\x20"),
|
||||||
|
("DF.TELECOM", "\x7f\x10"),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Files at the GSM application level
|
||||||
|
GSM_DFS = [
|
||||||
|
("LP", "\x6f\x05", "Language Preference"),
|
||||||
|
("IMSI", "\x6f\x07", "IMSI"),
|
||||||
|
("Kc","\x6f\x20", "Ciphering Key Kc"),
|
||||||
|
("PLMNsel", "\x6f\x30", "PLMN selector"),
|
||||||
|
("HPPLMN", "\x6f\x31", "Higher Priority PLMN search period"),
|
||||||
|
("ACMmax", "\x6f\x37", "ACM maximum value"),
|
||||||
|
("SST", "\x6f\x38", "SIM service table"),
|
||||||
|
("ACM", "\x6f\x39", "Accumulated call meter"),
|
||||||
|
("GID1", "\x6f\x3e", "Group Identifier Level 1"),
|
||||||
|
("GID2", "\x6f\x3f", "Group Identifier Level 2"),
|
||||||
|
("SPN", "\x6f\x46", "Service Provider Name"),
|
||||||
|
("PUCT", "\x6f\x41", "Price per unit and currency table"),
|
||||||
|
("CBMI", "\x6f\x45", "Cell broadcast message identifier selection"),
|
||||||
|
("BCCH", "\x6f\x74", "Broadcast control channels"),
|
||||||
|
("ACC", "\x6f\x78", "Access control class"),
|
||||||
|
("FPLMN", "\x6f\x7b", "Forbidden PLMNs"),
|
||||||
|
("LOCI", "\x6f\x7e", "Location Information"),
|
||||||
|
("AD", "\x6f\xAD", "Administrative Data"),
|
||||||
|
("Phase", "\x6f\xAE", "Phase identification"),
|
||||||
|
("VGCS", "\x6f\xB1", "Voice Group Call Service"),
|
||||||
|
("VGCSS", "\x6f\xB2", "Voice Group Call Service Status"),
|
||||||
|
("VBS", "\x6f\xB3", "Voice Broadcast Service"),
|
||||||
|
("VBSS", "\x6f\xB4", "Voice Broadcast Service Status"),
|
||||||
|
("eMLPP", "\x6f\xB5", "enhanced Multi Level Pre-emptyion and Priority"),
|
||||||
|
("AAeM", "\x6f\xB5", "Authomatic Answer for eEMLPP Service"),
|
||||||
|
("CBMID", "\x6f\x48", "Cell Broadcast Message Identifier for Data Download"),
|
||||||
|
("ECC", "\x6f\xB7", "Emergency Call Codes"),
|
||||||
|
("CBMIR", "\x6f\x50", "Cell broadcast message identifier range selection"),
|
||||||
|
("DCK", "\x6f\x2C", "De-personalization Control Keys"),
|
||||||
|
("CNL", "\x6f\x32", "Co-operative Network List"),
|
||||||
|
("NIA", "\x6f\x51", "Network's Indication of Alerting"),
|
||||||
|
("KcGPRS", "\x6f\x52", "GPRS Ciphering Key KcGPRS"),
|
||||||
|
("LOCIGPRS", "\x6f\x53", "GPRS Location Information"),
|
||||||
|
("SUME", "\x6f\x54", "SetUpMenu Elements"),
|
||||||
|
("PLMNwAcT", "\x6f\x60", "User controlled PLMN Selector with Access Technology"),
|
||||||
|
("OPLMNwAcT", "\x6f\x51", "Operator controlled PLMN Selector with Access Technology"),
|
||||||
|
("HPLMNwAcT", "\x6f\x62", "HPLMN Selector with Access Technology"),
|
||||||
|
("CPBCCH", "\x6f\x63", "CPBCCH Information"),
|
||||||
|
("InvScan", "\x6f\x64", "Investigation Scan"),
|
||||||
|
]
|
||||||
|
|
||||||
|
# According to TS 11.11 Chapter 9.3
|
||||||
|
type_of_file_names = { 0: 'RFU', 1: 'MF', 2: 'DF', 4: 'EF' }
|
||||||
|
struct_of_file_names = { 0: 'transparent',
|
||||||
|
1: 'linear fixed',
|
||||||
|
2: 'transparent',
|
||||||
|
3: 'cyclic' }
|
||||||
|
acc_cond_names = { 0: 'ALWAYS',
|
||||||
|
1: 'CHV1',
|
||||||
|
2: 'CHV2',
|
||||||
|
3: 'RFU',
|
||||||
|
4: 'ADM1',
|
||||||
|
5: 'ADM2',
|
||||||
|
6: 'ADM3',
|
||||||
|
7: 'ADM4',
|
||||||
|
8: 'ADM5',
|
||||||
|
9: 'ADM6',
|
||||||
|
10: 'ADM7',
|
||||||
|
11: 'ADM8',
|
||||||
|
12: 'ADM9',
|
||||||
|
13: 'ADM10',
|
||||||
|
14: 'ADM11',
|
||||||
|
15: 'NEW' }
|
||||||
ATRS = [
|
ATRS = [
|
||||||
("3bff9500ffc00a1f438031e073f62113574a334861324147d6", None),
|
("3bff9500ffc00a1f438031e073f62113574a334861324147d6", None),
|
||||||
|
("3b9a940092027593110001020200", None),
|
||||||
|
("3b989400939114010c020102", None),
|
||||||
|
#("3b991800118822334455667760", None),
|
||||||
|
#("3bdf96ff80b1fe451fc78031e073fe21136791150103040404ef", None),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def before_send(self, apdu):
|
||||||
|
if apdu.cla == 0x00:
|
||||||
|
apdu.CLA = self.CLA
|
||||||
|
|
||||||
|
return apdu
|
||||||
|
|
||||||
|
def cmd_run_gsm_algo(self, rand):
|
||||||
|
"""Perform the GSM A3/A8 algorithm.
|
||||||
|
RAND is the random challenge to be sent to the card."""
|
||||||
|
if len(rand) != 16:
|
||||||
|
rand2 = binascii.a2b_hex("".join(rand.split()))
|
||||||
|
else:
|
||||||
|
rand2 = rand
|
||||||
|
|
||||||
|
if len(rand2) != 16:
|
||||||
|
raise TypeError, "Need either exactly 16 binary bytes or 16 hexedecimal bytes for the RAND argument."
|
||||||
|
|
||||||
|
apdu = C_APDU(self.APDU_RUN_GSM_ALGO,
|
||||||
|
p1 = 0, p2 = 0, data = rand2)
|
||||||
|
|
||||||
|
result = self.send_apdu(apdu)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def cmd_cd_gsm(self):
|
||||||
|
"""Change into DF.GSM."""
|
||||||
|
apdu = C_APDU(self.APDU_SELECT_FILE, data = "\x7f\x20")
|
||||||
|
result = self.send_apdu(apdu)
|
||||||
|
return result
|
||||||
|
|
||||||
|
# def cmd_cd(self, dir = None):
|
||||||
|
# fid = None
|
||||||
|
# for n, f in self.INTERESTING_FILES:
|
||||||
|
# if n == dir:
|
||||||
|
# fid = f
|
||||||
|
# break
|
||||||
|
# if fid is None:
|
||||||
|
# return ISO_7816_4_Card.cmd_cd(self, dir)
|
||||||
|
# else:
|
||||||
|
# return ISO_7816_4_Card.change_dir(self, fid)
|
||||||
|
|
||||||
|
def change_dir(self, fid = None):
|
||||||
|
"Change to a child DF. Alternatively, change to MF if fid is None."
|
||||||
|
if fid is None:
|
||||||
|
return self.select_file(0, 0, "\x3f\x00")
|
||||||
|
else:
|
||||||
|
return self.select_file(0, 0, fid)
|
||||||
|
|
||||||
|
def cmd_status(self):
|
||||||
|
"""STATUS Command."""
|
||||||
|
apdu = C_APDU(self.APDU_STATUS, data="\xff")
|
||||||
|
result = self.send_apdu(apdu)
|
||||||
|
if len(result.data) > 0:
|
||||||
|
print utils.hexdump(result.data)
|
||||||
|
print self.sel_ret_decode(result.data)
|
||||||
|
|
||||||
|
def cmd_term_prof(self, data):
|
||||||
|
"""TERMINAL PROFILE Command."""
|
||||||
|
apdu = C_APDU(self.APDU_TERMINAL_PROFILE, data = data)
|
||||||
|
return self.send_apdu(apdu)
|
||||||
|
|
||||||
|
def cmd_envelope(self, data):
|
||||||
|
"""ENVELOPE Command."""
|
||||||
|
apdu = C_APDU(self.APDU_ENVELOPE, data = data)
|
||||||
|
return self.send_apdu(apdu)
|
||||||
|
|
||||||
|
def cmd_fetch(self, data):
|
||||||
|
"""FETCH Command."""
|
||||||
|
apdu = C_APDU(self.APDU_FETCH, data = data)
|
||||||
|
return self.send_apdu(apdu)
|
||||||
|
|
||||||
|
def cmd_term_resp(self, data):
|
||||||
|
"""TERMINAL RESPONSE Command."""
|
||||||
|
apdu = C_APDU(self.APDU_TERMINAL_RESPONSE, data = data)
|
||||||
|
return self.send_apdu(apdu)
|
||||||
|
|
||||||
|
def cmd_upd_binary(self, data):
|
||||||
|
"""Write to a transparent binary file."""
|
||||||
|
data_bin = binascii.a2b_hex("".join(data.split()))
|
||||||
|
apdu = C_APDU(self.APDU_UPD_BINARY, data = data_bin)
|
||||||
|
return self.send_apdu(apdu)
|
||||||
|
|
||||||
|
def cmd_selectfile(self, fid):
|
||||||
|
"""Select a file on the card."""
|
||||||
|
|
||||||
|
fid = binascii.a2b_hex("".join(fid.split()))
|
||||||
|
|
||||||
|
result = self.select_file(0, 0, fid)
|
||||||
|
if len(result.data) > 0:
|
||||||
|
print utils.hexdump(result.data)
|
||||||
|
print self.sel_ret_decode(result.data)
|
||||||
|
|
||||||
|
def sel_ret_decode(self, data):
|
||||||
|
#print "File: %s" % (data[
|
||||||
|
type_of_file = ord(data[6])
|
||||||
|
print "Type of File: %s" % (self.type_of_file_names[type_of_file])
|
||||||
|
if type_of_file == 4:
|
||||||
|
structure = ord(data[12])
|
||||||
|
print "Structure of File: %s" % (self.struct_of_file_names[structure])
|
||||||
|
if structure == 3:
|
||||||
|
if ord(data[7]) & 0x80:
|
||||||
|
print "INCREASE allowed"
|
||||||
|
else:
|
||||||
|
print "INCREASE not allowed"
|
||||||
|
if structure == 1 or structure == 3:
|
||||||
|
print "Record size: %u bytes" % ord(data[14])
|
||||||
|
#print "File Size: %u bytes" %
|
||||||
|
acc_cond = data[8:11]
|
||||||
|
self.acc_cond_decode(acc_cond)
|
||||||
|
status = ord(data[11])
|
||||||
|
if not status & 0x1:
|
||||||
|
print "Status: invalidated, "
|
||||||
|
if not status & 0x4:
|
||||||
|
print "not "
|
||||||
|
print "readable and updatable\n"
|
||||||
|
elif type_of_file == 2:
|
||||||
|
#print "Total unallocated memory in DF: %u bytes"
|
||||||
|
gsm_spec_data = data[13:]
|
||||||
|
print "Number of DFs : %u" % (ord(gsm_spec_data[1]))
|
||||||
|
print "Number of EFs : %u" % (ord(gsm_spec_data[2]))
|
||||||
|
print "Number of CHV : %u" % (ord(gsm_spec_data[3]))
|
||||||
|
print "CHV1 status : %s" % (self.chv_status_decode(gsm_spec_data[5]))
|
||||||
|
print "UNBLOCK CHV1 status : %s" % (self.chv_status_decode(gsm_spec_data[6]))
|
||||||
|
print "CHV2 status : %s" % (self.chv_status_decode(gsm_spec_data[7]))
|
||||||
|
print "UNBLOCK CHV2 status : %s" % (self.chv_status_decode(gsm_spec_data[8]))
|
||||||
|
|
||||||
|
def chv_status_decode(self, s):
|
||||||
|
status = ord(s)
|
||||||
|
if status & 0x80:
|
||||||
|
initialized = 1
|
||||||
|
else:
|
||||||
|
initialized = 0
|
||||||
|
return "Initialized: %u, Retries remaining: %u" % (initialized, status & 0xf)
|
||||||
|
|
||||||
|
def acc_cond_decode(self, acc_cond):
|
||||||
|
print "Access cond. READ/SEEK : %s" % (self.acc_cond_names[ord(acc_cond[0]) >> 4])
|
||||||
|
print "Access cond. UPDATE : %s" % (self.acc_cond_names[ord(acc_cond[0]) & 0xf])
|
||||||
|
print "Access cond. INCREASE : %s" % (self.acc_cond_names[ord(acc_cond[1]) >> 4])
|
||||||
|
print "Access cond. REHABILITATE: %s" % (self.acc_cond_names[ord(acc_cond[2]) >> 4])
|
||||||
|
print "Access cond. INVALIDATE : %s" % (self.acc_cond_names[ord(acc_cond[2]) & 0xf])
|
||||||
|
|
||||||
|
|
||||||
|
COMMANDS = dict(Card.COMMANDS)
|
||||||
|
COMMANDS.update(building_blocks.Card_with_read_binary.COMMANDS)
|
||||||
|
COMMANDS.update({
|
||||||
|
"gsm_run_algo" : cmd_run_gsm_algo,
|
||||||
|
#"cd" : cmd_cd,
|
||||||
|
"cd_df_gsm" : cmd_cd_gsm,
|
||||||
|
"gsm_status" : cmd_status,
|
||||||
|
# STK
|
||||||
|
"gsm_terminal_profile" : cmd_term_prof,
|
||||||
|
"gsm_envelope" : cmd_envelope,
|
||||||
|
"gsm_fetch" : cmd_fetch,
|
||||||
|
"gsm_terminal_response" : cmd_term_resp,
|
||||||
|
"gsm_select_file" : cmd_selectfile,
|
||||||
|
"update_binary" : cmd_upd_binary,
|
||||||
|
})
|
||||||
|
|
||||||
STATUS_WORDS = {
|
STATUS_WORDS = {
|
||||||
|
# TS 11.11 Chapter 9.4.1
|
||||||
|
#'9000': "Normal ending of the command"
|
||||||
|
#'91??': "Normal ending of the command, with extra information from proactive SIM"
|
||||||
|
'9E??': "Length '$(SW2)i (0x$(SW2)02x)' of the response data in case of SIM data dl error",
|
||||||
'9F??': "Length '%(SW2)i (0x%(SW2)02x)' of the response data",
|
'9F??': "Length '%(SW2)i (0x%(SW2)02x)' of the response data",
|
||||||
|
# TS 11.11 Chapter 9.4.2
|
||||||
|
'9300': "SIM Application Toolkit busy",
|
||||||
|
# TS 11.11 Chapter 9.4.3
|
||||||
'920?': lambda sw1, sw2: "Update successful but after using an internal retry routine '%i' times" % (sw2 % 16),
|
'920?': lambda sw1, sw2: "Update successful but after using an internal retry routine '%i' times" % (sw2 % 16),
|
||||||
'9240': "Memory problem",
|
'9240': "Memory problem",
|
||||||
|
# TS 11.11 Chapter 9.4.4
|
||||||
'9400': "No EF selected",
|
'9400': "No EF selected",
|
||||||
'9402': "Out of range (invalid address)",
|
'9402': "Out of range (invalid address)",
|
||||||
'9404': "- File ID not found\n- Pattern not found",
|
'9404': "- File ID not found\n- Pattern not found",
|
||||||
'9408': "File is inconsistent with the command",
|
'9408': "File is inconsistent with the command",
|
||||||
|
# TS 11.11 Chapter 9.4.5
|
||||||
'9802': "No CHV initialized",
|
'9802': "No CHV initialized",
|
||||||
'9804': "- Access condition not fulfilled\n- Unsuccessful CHV verification, at least one attempt left\n- unsuccesful UNBLOCK CHV verification, at least one attempt left\n- authentication failed",
|
'9804': "- Access condition not fulfilled\n- Unsuccessful CHV verification, at least one attempt left\n- unsuccesful UNBLOCK CHV verification, at least one attempt left\n- authentication failed",
|
||||||
'9808': "In contradiction with CHV status",
|
'9808': "In contradiction with CHV status",
|
||||||
'9810': "In contradiction with invalidation status",
|
'9810': "In contradiction with invalidation status",
|
||||||
'9840': "- Unsuccessful CHV verification, no attempt left\n- unsuccesful UNBLOCK CHV verification, no attempt left\n- CHV blocked\n- UNBLOCK CHV blocked",
|
'9840': "- Unsuccessful CHV verification, no attempt left\n- unsuccesful UNBLOCK CHV verification, no attempt left\n- CHV blocked\n- UNBLOCK CHV blocked",
|
||||||
'9850': "Increase cannot be performed, Max value reached",
|
'9850': "Increase cannot be performed, Max value reached",
|
||||||
|
# TS 11.11 Chapter 9.4.6
|
||||||
"67??": "Incorrect parameter P3",
|
"67??": "Incorrect parameter P3",
|
||||||
"\x67\x00": "Incorrect parameter P3 (ISO:Wrong length)",
|
"\x67\x00": "Incorrect parameter P3 (ISO:Wrong length)",
|
||||||
"6B??": "Incorrect parameter P1 or P2",
|
"6B??": "Incorrect parameter P1 or P2",
|
||||||
|
|
Loading…
Reference in New Issue