Skip to content

Commit

Permalink
pySim-read.py: fix reading and parsing of EF.MSISDN
Browse files Browse the repository at this point in the history
This change implements parsing of EF.MSISDN (and thus EF.ADN)
as per 3GPP TS 31.102, sections 4.2.26 and 4.4.2.3.

Example (commercial SIM card from 401/02):

  EF.MSISDN: ffffffffffffffffffffffffffff07917787028982f7ffffffffffff
  Decoded (NPI=1 ToN=1): +77782098287

Note that sysmoUSIM-SJS1 in the test setup has malformed
EF.MSISDN, so that's why the test output is changed.

Change-Id: Ie914ae83d787e3f1a90f9f305bffd45053b8c863
  • Loading branch information
herlesupreeth authored and axilirator committed Feb 14, 2020
1 parent d24f163 commit 4b1c763
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 5 deletions.
8 changes: 5 additions & 3 deletions pySim-read.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
import simplejson as json

from pySim.commands import SimCardCommands
from pySim.utils import h2b, swap_nibbles, rpad, dec_imsi, dec_iccid, format_xplmn_w_act, dec_spn
from pySim.utils import h2b, swap_nibbles, rpad, dec_imsi, dec_iccid, dec_msisdn, format_xplmn_w_act, dec_spn


def parse_options():
Expand Down Expand Up @@ -186,8 +186,10 @@ def parse_options():
# print(scc.record_size(['3f00', '7f10', '6f40']))
(res, sw) = scc.read_record(['3f00', '7f10', '6f40'], 1)
if sw == '9000':
if res[1] != 'f':
print("MSISDN: %s" % (res,))
res_dec = dec_msisdn(res)
if res_dec is not None:
# (npi, ton, msisdn) = res_dec
print("MSISDN (NPI=%d ToN=%d): %s" % res_dec)
else:
print("MSISDN: Not available")
else:
Expand Down
41 changes: 41 additions & 0 deletions pySim/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,3 +258,44 @@ def derive_mnc(digit1, digit2, digit3=0x0f):
mnc += digit2

return mnc

def dec_msisdn(ef_msisdn):
"""
Decode MSISDN from EF.MSISDN or EF.ADN (same structure).
See 3GPP TS 31.102, section 4.2.26 and 4.4.2.3.
"""

# Convert from str to (kind of) 'bytes'
ef_msisdn = h2b(ef_msisdn)

# Make sure mandatory fields are present
if len(ef_msisdn) < 14:
raise ValueError("EF.MSISDN is too short")

# Skip optional Alpha Identifier
xlen = len(ef_msisdn) - 14
msisdn_lhv = ef_msisdn[xlen:]

# Parse the length (in bytes) of the BCD encoded number
bcd_len = ord(msisdn_lhv[0])
# BCD length = length of dial num (max. 10 bytes) + 1 byte ToN and NPI
if bcd_len == 0xff:
return None
elif bcd_len > 11 or bcd_len < 1:
raise ValueError("Length of MSISDN (%d bytes) is out of range" % bcd_len)

# Parse ToN / NPI
ton = (ord(msisdn_lhv[1]) >> 4) & 0x07
npi = ord(msisdn_lhv[1]) & 0x0f
bcd_len -= 1

# No MSISDN?
if not bcd_len:
return (npi, ton, None)

msisdn = swap_nibbles(b2h(msisdn_lhv[2:][:bcd_len])).rstrip('f')
# International number 10.5.118/3GPP TS 24.008
if (ton & 0x01) == 0x01:
msisdn = '+' + msisdn

return (npi, ton, msisdn)
2 changes: 1 addition & 1 deletion pysim-testdata/sysmoISIM-SJA2.ok
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ HPLMNAcT:
ffffff0000 # unused

ACC: 0001
MSISDN: Not available
MSISDN (NPI=1 ToN=1): +1234
AD: 00000002
Done !

2 changes: 1 addition & 1 deletion pysim-testdata/sysmoUSIM-SJS1.ok
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ HPLMNAcT:
ffffff0000 # unused

ACC: 0008
MSISDN: Not available
MSISDN: Can't read file -- Length of MSISDN (136 bytes) is out of range
AD: 00000002
Done !

0 comments on commit 4b1c763

Please sign in to comment.