Hello Silvain,
please find attached a patch for pySIM which I put together today after
some work to get the extra parameters which I needed on the
sysmoUSIM-GR1. Don't know if it only works for those cards.
This fixes some bugs in setting the IMSI and also adds support for
selecting USIM and writing binary/records in there. I have also added
some parameters like MSISDN or the forbidden MCC to black-list other
national networks, in the idea that one would provision on the test
001/01 network. The data formats are not so well defined or clean as I
was on a get-it-done schedule and did not actually read the specs.
Anyway, the result works fine for me.
Otherwise I could only use pySIM with the GemPC Express reader. I read
that you have a PC Twin Reader which seems to be more common, but I am
getting the following with that, so any help would be appreciated:
Programming ...
Traceback (most recent call last):
File "./pySim-prog.py", line 544, in <module>
card.program(cp)
File
"/root/svn/svnsrv.fokus.fraunhofer.de_OpenEPC/pysim/pySim/cards.py",
line 364, in program
data, sw = self._scc._tp.send_apdu_checksw("0099000033" + par)
File
"/root/svn/svnsrv.fokus.fraunhofer.de_OpenEPC/pysim/pySim/transport/__init__.py",
line 88, in send_apdu_checksw
rv = self.send_apdu(pdu)
File
"/root/svn/svnsrv.fokus.fraunhofer.de_OpenEPC/pysim/pySim/transport/__init__.py",
line 69, in send_apdu
data, sw = self.send_apdu_raw(pdu)
File
"/root/svn/svnsrv.fokus.fraunhofer.de_OpenEPC/pysim/pySim/transport/pcsc.py",
line 75, in send_apdu_raw
data, sw1, sw2 = self._con.transmit(apdu)
File
"/usr/lib/python2.7/dist-packages/smartcard/CardConnectionDecorator.py",
line 82, in transmit
return self.component.transmit(bytes, protocol)
File "/usr/lib/python2.7/dist-packages/smartcard/CardConnection.py",
line 140, in transmit
data, sw1, sw2 = self.doTransmit(bytes, protocol)
File
"/usr/lib/python2.7/dist-packages/smartcard/pcsc/PCSCCardConnection.py",
line 175, in doTransmit
raise CardConnectionException('Failed to transmit with protocol ' +
dictProtocolHeader[pcscprotocolheader] + '. ' +
SCardGetErrorMessage(hresult))
smartcard.Exceptions.CardConnectionException: Failed to transmit with
protocol T0. Transaction failed.
P.S. I must apologize if the patch is crappy, as I could not yet be
bothered to read a book or something on python.
Cheers,
-Dragos
--
-----------------------------------------
Dipl. Eng. Dragos Vingarzan
Fraunhofer FOKUS/NGNI
Kaiserin-Augusta-Allee 31
10589 Berlin,Germany
Phone +49 (0)30 - 3463 - 7385
Mobile +49 (0)176 - 48 32 16 00
Web www.fokus.fraunhofer.de www.openepc.net www.openimscore.org
-----------------------------------------------------------------
diff --git a/pySim-prog.py b/pySim-prog.py
index 46b1842..ccf3d4f 100755
--- a/pySim-prog.py
+++ b/pySim-prog.py
@@ -83,6 +83,10 @@ def parse_options():
help="Mobile Network Code [default: %default]",
default=55,
)
+ parser.add_option("-f", "--fmcc", dest="fmcc", type="int",
+ help="Forbidden Mobile Country Code [default: %default]",
+ default=262,
+ )
parser.add_option("-m", "--smsc", dest="smsc",
help="SMSP [default: '00 + country code + 5555']",
)
@@ -96,6 +100,9 @@ def parse_options():
parser.add_option("-i", "--imsi", dest="imsi",
help="International Mobile Subscriber Identity",
)
+ parser.add_option("-a", "--msisdn", dest="msisdn",
+ help="MS ISDN Number",
+ )
parser.add_option("-k", "--ki", dest="ki",
help="Ki (default is to randomize)",
)
@@ -335,7 +342,9 @@ def gen_parameters(opts):
else:
opc = ''.join(['%02x' % random.randrange(0,256) for i in range(16)])
-
+ msisdn = opts.msisdn
+ fmcc = opts.fmcc
+
# Return that
return {
'name' : opts.name,
@@ -346,6 +355,9 @@ def gen_parameters(opts):
'smsp' : smsp,
'ki' : ki,
'opc' : opc,
+ 'msisdn' : msisdn,
+ 'fmcc' : fmcc,
+
}
@@ -359,6 +371,8 @@ def print_parameters(params):
> IMSI : %(imsi)s
> Ki : %(ki)s
> OPC : %(opc)s
+ > MSISDN : %(msisdn)s
+ > ForbMCC : %(fmcc)s
""" % params
@@ -366,7 +380,7 @@ def write_parameters(opts, params):
# CSV
if opts.write_csv:
import csv
- row = ['name', 'iccid', 'mcc', 'mnc', 'imsi', 'smsp', 'ki', 'opc']
+ row = ['name', 'iccid', 'mcc', 'mnc', 'imsi', 'smsp', 'ki', 'opc', 'msisdn']
f = open(opts.write_csv, 'a')
cw = csv.writer(f)
cw.writerow([params[x] for x in row])
diff --git a/pySim/cards.py b/pySim/cards.py
index 88eceb0..c9381f6 100644
--- a/pySim/cards.py
+++ b/pySim/cards.py
@@ -35,11 +35,30 @@ class Card(object):
def _e_imsi(self, imsi):
"""Converts a string imsi into the value of the EF"""
- l = (len(imsi) + 1) // 2 # Required bytes
+ l = (len(imsi) + 1) // 2 + (len(imsi)+1)%2 # Required bytes
oe = len(imsi) & 1 # Odd (1) / Even (0)
- ei = '%02x' % l + swap_nibbles(lpad('%01x%s' % ((oe<<3)|1, imsi), 16))
+ ei = "%01x%s" % ((oe<<3)|1, imsi)
+ if len(ei) & 1 == 1 :
+ ei += "f"
+ ei = '%02x' % l + swap_nibbles(ei)
return ei
+ def _e_bcd(self, bcd):
+ l = (len(bcd)) // 2 + (len(bcd))%2 # Required bytes
+ ebcd = bcd
+ if len(ebcd) & 1 == 1 :
+ ebcd += "f"
+ ebcd = swap_nibbles(ebcd)
+ return ebcd
+
+ def _e_mcc_mnc(self, mcc, mnc):
+ mccmnc = self._e_bcd("%03d" % mcc)+self._e_bcd("%02d" % mnc)
+ return mccmnc
+
+ def _e_ascii(self, txt):
+ etxt= txt.encode("hex")
+ return etxt
+
def _e_plmn(self, mcc, mnc):
"""Converts integer MCC/MNC into 6 bytes for EF"""
return swap_nibbles(lpad('%d' % mcc, 3) + lpad('%d' % mnc, 3))
@@ -344,6 +363,47 @@ class SysmoUSIMgr1(Card):
)
data, sw = self._scc._tp.send_apdu_checksw("0099000033" + par)
+ # SPN (Service Provider Name)
+ spn = "0181%02x00" % len(p['name'])
+ spn += self._e_ascii(p['name'])
+ print "Setting SPN: ",spn
+ data, sw = self._scc.update_binary_usim(['7fff', '6f46'], spn)
+
+ # MSISDN
+ msisdn = self._e_ascii("My Number")
+ while (len(msisdn)<14*2):
+ msisdn += "ff"
+ msisdn += "%02x91" % len(p['msisdn'])
+ msisdn += self._e_bcd(p['msisdn'])
+ while (len(msisdn)<28*2):
+ msisdn += "ff"
+ print "Setting MSISDN: ",msisdn
+ data, sw = self._scc.update_record_usim(['7fff', '6f40'], 1, msisdn, True)
+
+ # PLMNwAcT
+ plmnwact = self._e_mcc_mnc(p['mcc'],p['mnc'])
+ plmnwact += "80c0"
+ for i in range(3): # just to delete the next 3
+ plmnwact += "ffffff0000"
+ print "Setting PLMNwAcT: ",plmnwact
+ data, sw = self._scc.update_binary_usim(['7fff', '6f60'], plmnwact)
+
+ # OPLMNwAcT
+ print "Setting OPLMNwAcT: ",plmnwact
+ data, sw = self._scc.update_binary_usim(['7fff', '6f61'], plmnwact)
+
+ # HPLMNwAcT
+ print "Setting HPLMNwAcT: ",plmnwact
+ data, sw = self._scc.update_binary_usim(['7fff', '6f62'], plmnwact)
+
+ # FPLMN - forbid all other local networks
+ fplmn = ""
+ for i in range(1,9):
+ fplmn += self._e_mcc_mnc(p['fmcc'],i)
+ print "Setting FPLMN: ",fplmn
+ data, sw = self._scc.update_binary_usim(['7fff', '6f7b'], fplmn)
+
+
def erase(self):
return
diff --git a/pySim/commands.py b/pySim/commands.py
index f650272..b8a89b9 100644
--- a/pySim/commands.py
+++ b/pySim/commands.py
@@ -36,6 +36,14 @@ class SimCardCommands(object):
rv.append(data)
return rv
+ def select_file_usim(self, dir_list):
+ data, sw = self._tp.send_apdu_checksw("00a4040c10" + "A0000000871002FF86FFFF89FFFFFFFF")
+ rv = []
+ for i in dir_list:
+ data, sw = self._tp.send_apdu_checksw("00a4000c02" + i)
+ rv.append(data)
+ return rv
+
def read_binary(self, ef, length=None, offset=0):
if not hasattr(type(ef), '__iter__'):
ef = [ef]
@@ -52,6 +60,13 @@ class SimCardCommands(object):
pdu = 'a0d6%04x%02x' % (offset, len(data)/2) + data
return self._tp.send_apdu_checksw(pdu)
+ def update_binary_usim(self, ef, data, offset=0):
+ if not hasattr(type(ef), '__iter__'):
+ ef = [ef]
+ self.select_file_usim(ef)
+ pdu = '00d6%04x%02x' % (offset, len(data)/2) + data
+ return self._tp.send_apdu_checksw(pdu)
+
def read_record(self, ef, rec_no):
if not hasattr(type(ef), '__iter__'):
ef = [ef]
@@ -73,6 +88,19 @@ class SimCardCommands(object):
pdu = ('a0dc%02x04%02x' % (rec_no, rec_length)) + data
return self._tp.send_apdu_checksw(pdu)
+ def update_record_usim(self, ef, rec_no, data, force_len=False):
+ if not hasattr(type(ef), '__iter__'):
+ ef = [ef]
+ r = self.select_file_usim(ef)
+ if not force_len:
+ rec_length = int(r[-1][28:30], 16)
+ if (len(data)/2 != rec_length):
+ raise ValueError('Invalid data length (expected %d, got %d)' % (rec_length, len(data)/2))
+ else:
+ rec_length = len(data)/2
+ pdu = ('00dc%02x04%02x' % (rec_no, rec_length)) + data
+ return self._tp.send_apdu_checksw(pdu)
+
def record_size(self, ef):
r = self.select_file(ef)
return int(r[-1][28:30], 16)
diff --git a/pySim/transport/__init__.py b/pySim/transport/__init__.py
index dd04bba..f0fea5c 100644
--- a/pySim/transport/__init__.py
+++ b/pySim/transport/__init__.py
@@ -65,8 +65,11 @@ class LinkBase(object):
data : string (in hex) of returned data (ex. "074F4EFFFF")
sw : string (in hex) of status word (ex. "9000")
"""
+ #print "Tx--> APDU %s" % pdu
data, sw = self.send_apdu_raw(pdu)
+ #print "Rx--> APDU %s%s" % (data,sw)
+
if (sw is not None) and (sw[0:2] == '9f'):
pdu_gr = pdu[0:2] + 'c00000' + sw[2:4]
data, sw = self.send_apdu_raw(pdu_gr)