laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/35279?usp=email )
Change subject: move {enc,dec}_addr_tlv functions from pySim.util to pySim.legacy.util ......................................................................
move {enc,dec}_addr_tlv functions from pySim.util to pySim.legacy.util
In the previous commit we've stopped using those functions from modern pySim-shell code. Hence, the only remaining user is the legacy tools, so we can move the code to the legacy module.
Change-Id: I6f18ccb36fc33bc204c01f9ece135676510e67ec --- M pySim/legacy/cards.py M pySim/legacy/utils.py M pySim/utils.py 3 files changed, 135 insertions(+), 123 deletions(-)
Approvals: laforge: Looks good to me, approved fixeria: Looks good to me, but someone else must approve Jenkins Builder: Verified
diff --git a/pySim/legacy/cards.py b/pySim/legacy/cards.py index 496ce78..9d1e2c1 100644 --- a/pySim/legacy/cards.py +++ b/pySim/legacy/cards.py @@ -8,11 +8,10 @@
from pySim.cards import SimCardBase, UiccCardBase from pySim.utils import dec_iccid, enc_iccid, dec_imsi, enc_imsi, dec_msisdn, enc_msisdn -from pySim.utils import dec_addr_tlv, enc_addr_tlv from pySim.utils import enc_plmn, get_addr_type from pySim.utils import is_hex, h2b, b2h, h2s, s2h, lpad, rpad from pySim.legacy.utils import enc_ePDGSelection, format_xplmn_w_act, format_xplmn, dec_st, enc_st -from pySim.legacy.utils import format_ePDGSelection +from pySim.legacy.utils import format_ePDGSelection, dec_addr_tlv, enc_addr_tlv from pySim.legacy.ts_51_011 import EF, DF from pySim.legacy.ts_31_102 import EF_USIM_ADF_map from pySim.legacy.ts_31_103 import EF_ISIM_ADF_map diff --git a/pySim/legacy/utils.py b/pySim/legacy/utils.py index 1b6b5d1..cf2416e 100644 --- a/pySim/legacy/utils.py +++ b/pySim/legacy/utils.py @@ -20,7 +20,7 @@ # along with this program. If not, see http://www.gnu.org/licenses/. #
-from pySim.utils import Hexstr, rpad, enc_plmn +from pySim.utils import Hexstr, rpad, enc_plmn, h2i, i2s, s2h from pySim.utils import dec_xplmn_w_act, dec_xplmn, dec_mcc_from_plmn, dec_mnc_from_plmn
def hexstr_to_Nbytearr(s, nbytes): @@ -210,3 +210,123 @@ res['epdg_priority'] = epdg_priority_str res['epdg_fqdn_format'] = epdg_fqdn_format_str == '00' and 'Operator Identifier FQDN' or 'Location based FQDN' return res + + +def first_TLV_parser(bytelist): + ''' + first_TLV_parser([0xAA, 0x02, 0xAB, 0xCD, 0xFF, 0x00]) -> (170, 2, [171, 205]) + + parses first TLV format record in a list of bytelist + returns a 3-Tuple: Tag, Length, Value + Value is a list of bytes + parsing of length is ETSI'style 101.220 + ''' + Tag = bytelist[0] + if bytelist[1] == 0xFF: + Len = bytelist[2]*256 + bytelist[3] + Val = bytelist[4:4+Len] + else: + Len = bytelist[1] + Val = bytelist[2:2+Len] + return (Tag, Len, Val) + + +def TLV_parser(bytelist): + ''' + TLV_parser([0xAA, ..., 0xFF]) -> [(T, L, [V]), (T, L, [V]), ...] + + loops on the input list of bytes with the "first_TLV_parser()" function + returns a list of 3-Tuples + ''' + ret = [] + while len(bytelist) > 0: + T, L, V = first_TLV_parser(bytelist) + if T == 0xFF: + # padding bytes + break + ret.append((T, L, V)) + # need to manage length of L + if L > 0xFE: + bytelist = bytelist[L+4:] + else: + bytelist = bytelist[L+2:] + return ret + + +def dec_addr_tlv(hexstr): + """ + Decode hex string to get EF.P-CSCF Address or EF.ePDGId or EF.ePDGIdEm. + See 3GPP TS 31.102 version 13.4.0 Release 13, section 4.2.8, 4.2.102 and 4.2.104. + """ + + # Convert from hex str to int bytes list + addr_tlv_bytes = h2i(hexstr) + + # Get list of tuples containing parsed TLVs + tlvs = TLV_parser(addr_tlv_bytes) + + for tlv in tlvs: + # tlv = (T, L, [V]) + # T = Tag + # L = Length + # [V] = List of value + + # Invalid Tag value scenario + if tlv[0] != 0x80: + continue + + # Empty field - Zero length + if tlv[1] == 0: + continue + + # Uninitialized field + if all([v == 0xff for v in tlv[2]]): + continue + + # First byte in the value has the address type + addr_type = tlv[2][0] + # TODO: Support parsing of IPv6 + # Address Type: 0x00 (FQDN), 0x01 (IPv4), 0x02 (IPv6), other (Reserved) + if addr_type == 0x00: # FQDN + # Skip address tye byte i.e. first byte in value list + content = tlv[2][1:] + return (i2s(content), '00') + + elif addr_type == 0x01: # IPv4 + # Skip address tye byte i.e. first byte in value list + # Skip the unused byte in Octect 4 after address type byte as per 3GPP TS 31.102 + ipv4 = tlv[2][2:] + content = '.'.join(str(x) for x in ipv4) + return (content, '01') + else: + raise ValueError("Invalid address type") + + return (None, None) + + +def enc_addr_tlv(addr, addr_type='00'): + """ + Encode address TLV object used in EF.P-CSCF Address, EF.ePDGId and EF.ePDGIdEm. + See 3GPP TS 31.102 version 13.4.0 Release 13, section 4.2.8, 4.2.102 and 4.2.104. + + Default values: + - addr_type: 00 - FQDN format of Address + """ + + s = "" + + # TODO: Encoding of IPv6 address + if addr_type == '00': # FQDN + hex_str = s2h(addr) + s += '80' + ('%02x' % ((len(hex_str)//2)+1)) + '00' + hex_str + elif addr_type == '01': # IPv4 + ipv4_list = addr.split('.') + ipv4_str = "" + for i in ipv4_list: + ipv4_str += ('%02x' % (int(i))) + + # Unused bytes shall be set to 'ff'. i.e 4th Octet after Address Type is not used + # IPv4 Address is in octet 5 to octet 8 of the TLV data object + s += '80' + ('%02x' % ((len(ipv4_str)//2)+2)) + '01' + 'ff' + ipv4_str + + return s diff --git a/pySim/utils.py b/pySim/utils.py index 23b26f9..aac9877 100644 --- a/pySim/utils.py +++ b/pySim/utils.py @@ -712,126 +712,6 @@ return ('%02x' % bcd_len) + ('%02x' % npi_ton) + bcd + ("ff" * 2)
-def first_TLV_parser(bytelist): - ''' - first_TLV_parser([0xAA, 0x02, 0xAB, 0xCD, 0xFF, 0x00]) -> (170, 2, [171, 205]) - - parses first TLV format record in a list of bytelist - returns a 3-Tuple: Tag, Length, Value - Value is a list of bytes - parsing of length is ETSI'style 101.220 - ''' - Tag = bytelist[0] - if bytelist[1] == 0xFF: - Len = bytelist[2]*256 + bytelist[3] - Val = bytelist[4:4+Len] - else: - Len = bytelist[1] - Val = bytelist[2:2+Len] - return (Tag, Len, Val) - - -def TLV_parser(bytelist): - ''' - TLV_parser([0xAA, ..., 0xFF]) -> [(T, L, [V]), (T, L, [V]), ...] - - loops on the input list of bytes with the "first_TLV_parser()" function - returns a list of 3-Tuples - ''' - ret = [] - while len(bytelist) > 0: - T, L, V = first_TLV_parser(bytelist) - if T == 0xFF: - # padding bytes - break - ret.append((T, L, V)) - # need to manage length of L - if L > 0xFE: - bytelist = bytelist[L+4:] - else: - bytelist = bytelist[L+2:] - return ret - - -def dec_addr_tlv(hexstr): - """ - Decode hex string to get EF.P-CSCF Address or EF.ePDGId or EF.ePDGIdEm. - See 3GPP TS 31.102 version 13.4.0 Release 13, section 4.2.8, 4.2.102 and 4.2.104. - """ - - # Convert from hex str to int bytes list - addr_tlv_bytes = h2i(hexstr) - - # Get list of tuples containing parsed TLVs - tlvs = TLV_parser(addr_tlv_bytes) - - for tlv in tlvs: - # tlv = (T, L, [V]) - # T = Tag - # L = Length - # [V] = List of value - - # Invalid Tag value scenario - if tlv[0] != 0x80: - continue - - # Empty field - Zero length - if tlv[1] == 0: - continue - - # Uninitialized field - if all([v == 0xff for v in tlv[2]]): - continue - - # First byte in the value has the address type - addr_type = tlv[2][0] - # TODO: Support parsing of IPv6 - # Address Type: 0x00 (FQDN), 0x01 (IPv4), 0x02 (IPv6), other (Reserved) - if addr_type == 0x00: # FQDN - # Skip address tye byte i.e. first byte in value list - content = tlv[2][1:] - return (i2s(content), '00') - - elif addr_type == 0x01: # IPv4 - # Skip address tye byte i.e. first byte in value list - # Skip the unused byte in Octect 4 after address type byte as per 3GPP TS 31.102 - ipv4 = tlv[2][2:] - content = '.'.join(str(x) for x in ipv4) - return (content, '01') - else: - raise ValueError("Invalid address type") - - return (None, None) - - -def enc_addr_tlv(addr, addr_type='00'): - """ - Encode address TLV object used in EF.P-CSCF Address, EF.ePDGId and EF.ePDGIdEm. - See 3GPP TS 31.102 version 13.4.0 Release 13, section 4.2.8, 4.2.102 and 4.2.104. - - Default values: - - addr_type: 00 - FQDN format of Address - """ - - s = "" - - # TODO: Encoding of IPv6 address - if addr_type == '00': # FQDN - hex_str = s2h(addr) - s += '80' + ('%02x' % ((len(hex_str)//2)+1)) + '00' + hex_str - elif addr_type == '01': # IPv4 - ipv4_list = addr.split('.') - ipv4_str = "" - for i in ipv4_list: - ipv4_str += ('%02x' % (int(i))) - - # Unused bytes shall be set to 'ff'. i.e 4th Octet after Address Type is not used - # IPv4 Address is in octet 5 to octet 8 of the TLV data object - s += '80' + ('%02x' % ((len(ipv4_str)//2)+2)) + '01' + 'ff' + ipv4_str - - return s - - def is_hex(string: str, minlen: int = 2, maxlen: Optional[int] = None) -> bool: """ Check if a string is a valid hexstring