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)

Reply via email to