From 346e2aeb01b86c618cc112d179e6720e169adf82 Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Sun, 3 Aug 2025 23:26:23 +0200 Subject: [PATCH] add test_configurable_parameters.py Change-Id: Ia55f0d11f8197ca15a948a83a34b3488acf1a0b4 --- pySim/esim/saip/personalization.py | 20 ++ tests/unittests/smdpp_data | 1 + .../unittests/test_configurable_parameters.py | 258 ++++++++++++++ .../unittests/xo/test_configurable_parameters | 336 ++++++++++++++++++ 4 files changed, 615 insertions(+) create mode 120000 tests/unittests/smdpp_data create mode 100755 tests/unittests/test_configurable_parameters.py create mode 100644 tests/unittests/xo/test_configurable_parameters diff --git a/pySim/esim/saip/personalization.py b/pySim/esim/saip/personalization.py index e3467ca9..e1c1d57d 100644 --- a/pySim/esim/saip/personalization.py +++ b/pySim/esim/saip/personalization.py @@ -209,6 +209,26 @@ class ConfigurableParameter(abc.ABC, metaclass=ClassVarMeta): Write the given val in the right format in all the right places in pes.""" pass + @classmethod + def get_value_from_pes(cls, pes: ProfileElementSequence): + """Same as get_values_from_pes() but expecting a single value. + get_values_from_pes() may return values like this: + [{ 'AlgorithmID': 'Milenage' }, { 'AlgorithmID': 'Milenage' }] + This ensures that all these entries are identical and would return only + { 'AlgorithmID': 'Milenage' }. + + This is relevant for any profile element that may appear multiple times in the same PES (only a few), + where each occurrence should reflect the same value (all currently known parameters). + """ + + val = None + for v in cls.get_values_from_pes(pes): + if val is None: + val = v + elif val != v: + raise ValueError(f'get_value_from_pes(): got distinct values: {val!r} != {v!r}') + return val + @classmethod @abc.abstractmethod def get_values_from_pes(cls, pes: ProfileElementSequence) -> Generator: diff --git a/tests/unittests/smdpp_data b/tests/unittests/smdpp_data new file mode 120000 index 00000000..a2d60f8e --- /dev/null +++ b/tests/unittests/smdpp_data @@ -0,0 +1 @@ +../../smdpp-data \ No newline at end of file diff --git a/tests/unittests/test_configurable_parameters.py b/tests/unittests/test_configurable_parameters.py new file mode 100755 index 00000000..d882af60 --- /dev/null +++ b/tests/unittests/test_configurable_parameters.py @@ -0,0 +1,258 @@ +#!/usr/bin/env python3 + +# (C) 2025 by sysmocom - s.f.m.c. GmbH +# +# Author: Neels Hofmeyr +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import io +import sys +import unittest +from importlib import resources +from osmocom.utils import hexstr +from pySim.esim.saip import ProfileElementSequence +import pySim.esim.saip.personalization as p13n +import smdpp_data.upp + +import xo +update_expected_output = False + +def valstr(val): + if isinstance(val, io.BytesIO): + val = val.getvalue() + if isinstance(val, bytearray): + val = bytes(val) + return f'{val!r}' + +def valtypestr(val): + if isinstance(val, dict): + types = [] + for v in val.values(): + types.append(f'{type(v).__name__}') + + val_type = '{' + ', '.join(types) + '}' + else: + val_type = f'{type(val).__name__}' + return f'{valstr(val)}:{val_type}' + +class ConfigurableParameterTest(unittest.TestCase): + + def test_parameters(self): + + upp_fnames = ( + 'TS48v5_SAIP2.1A_NoBERTLV.der', + 'TS48v5_SAIP2.3_BERTLV_SUCI.der', + 'TS48v5_SAIP2.1B_NoBERTLV.der', + 'TS48v5_SAIP2.3_NoBERTLV.der', + ) + + class Paramtest: + def __init__(self, param_cls, val, expect_val, expect_clean_val=None): + self.param_cls = param_cls + self.val = val + self.expect_clean_val = expect_clean_val + self.expect_val = expect_val + + param_tests = [ + Paramtest(param_cls=p13n.Imsi, val='123456', + expect_clean_val=str('123456'), + expect_val={'IMSI': hexstr('123456'), + 'IMSI-ACC': '0040'}), + Paramtest(param_cls=p13n.Imsi, val=int(123456), + expect_val={'IMSI': hexstr('123456'), + 'IMSI-ACC': '0040'}), + + Paramtest(param_cls=p13n.Imsi, val='123456789012345', + expect_clean_val=str('123456789012345'), + expect_val={'IMSI': hexstr('123456789012345'), + 'IMSI-ACC': '0020'}), + Paramtest(param_cls=p13n.Imsi, val=int(123456789012345), + expect_val={'IMSI': hexstr('123456789012345'), + 'IMSI-ACC': '0020'}), + + Paramtest(param_cls=p13n.Puk1, + val='12345678', + expect_clean_val=b'12345678', + expect_val='12345678'), + + Paramtest(param_cls=p13n.Puk2, + val='12345678', + expect_clean_val=b'12345678', + expect_val='12345678'), + + Paramtest(param_cls=p13n.Pin1, + val='1234', + expect_clean_val=b'1234\xff\xff\xff\xff', + expect_val='1234'), + Paramtest(param_cls=p13n.Pin1, + val='123456', + expect_clean_val=b'123456\xff\xff', + expect_val='123456'), + Paramtest(param_cls=p13n.Pin1, + val='12345678', + expect_clean_val=b'12345678', + expect_val='12345678'), + + Paramtest(param_cls=p13n.Adm1, + val='1234', + expect_clean_val=b'1234\xff\xff\xff\xff', + expect_val='1234'), + Paramtest(param_cls=p13n.Adm1, + val='123456', + expect_clean_val=b'123456\xff\xff', + expect_val='123456'), + Paramtest(param_cls=p13n.Adm1, + val='12345678', + expect_clean_val=b'12345678', + expect_val='12345678'), + + Paramtest(param_cls=p13n.AlgorithmID, + val='Milenage', + expect_clean_val=1, + expect_val='Milenage'), + Paramtest(param_cls=p13n.AlgorithmID, + val='TUAK', + expect_clean_val=2, + expect_val='TUAK'), + Paramtest(param_cls=p13n.AlgorithmID, + val='usim-test', + expect_clean_val=3, + expect_val='usim-test'), + + Paramtest(param_cls=p13n.K, + val='01020304050607080910111213141516', + expect_clean_val=b'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16', + expect_val='01020304050607080910111213141516'), + Paramtest(param_cls=p13n.K, + val=b'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16', + expect_clean_val=b'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16', + expect_val='01020304050607080910111213141516'), + Paramtest(param_cls=p13n.K, + val=bytearray(b'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16'), + expect_clean_val=b'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16', + expect_val='01020304050607080910111213141516'), + + Paramtest(param_cls=p13n.Opc, + val='01020304050607080910111213141516', + expect_clean_val=b'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16', + expect_val='01020304050607080910111213141516'), + Paramtest(param_cls=p13n.Opc, + val=b'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16', + expect_clean_val=b'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16', + expect_val='01020304050607080910111213141516'), + Paramtest(param_cls=p13n.Opc, + val=bytearray(b'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16'), + expect_clean_val=b'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16', + expect_val='01020304050607080910111213141516'), + ] + + # SdKey classes don't make sense yet, will come in Ic92ddea6e1fad8167ea75baf78ffc3eb419838c4 + + outputs = [] + + for upp_fname in upp_fnames: + test_idx = -1 + try: + + der = resources.read_binary(smdpp_data.upp, upp_fname) + + for t in param_tests: + test_idx += 1 + logloc = f'{upp_fname} {t.param_cls.__name__}(val={valtypestr(t.val)})' + + param = None + try: + param = t.param_cls() + param.input_value = t.val + param.validate() + except ValueError as e: + raise ValueError(f'{logloc}: {e}') from e + + clean_val = param.value + logloc = f'{logloc} clean_val={valtypestr(clean_val)}' + if t.expect_clean_val is not None and t.expect_clean_val != clean_val: + raise ValueError(f'{logloc}: expected' + f' expect_clean_val={valtypestr(t.expect_clean_val)}') + + # on my laptop, deepcopy is about 30% slower than decoding the DER from scratch: + # pes = copy.deepcopy(orig_pes) + pes = ProfileElementSequence.from_der(der) + try: + param.apply(pes) + except ValueError as e: + raise ValueError(f'{logloc} apply_val(clean_val): {e}') from e + + changed_der = pes.to_der() + + pes2 = ProfileElementSequence.from_der(changed_der) + + read_back_val = t.param_cls.get_value_from_pes(pes2) + + # compose log string to show the precise type of dict values + if isinstance(read_back_val, dict): + types = set() + for v in read_back_val.values(): + types.add(f'{type(v).__name__}') + + read_back_val_type = '{' + ', '.join(types) + '}' + else: + read_back_val_type = f'{type(read_back_val).__name__}' + + logloc = (f'{logloc} read_back_val={valtypestr(read_back_val)}') + + if isinstance(read_back_val, dict) and not t.param_cls.get_name() in read_back_val.keys(): + raise ValueError(f'{logloc}: expected to find name {t.param_cls.get_name()!r} in read_back_val') + + expect_val = t.expect_val + if not isinstance(expect_val, dict): + expect_val = { t.param_cls.get_name(): expect_val } + if read_back_val != expect_val: + raise ValueError(f'{logloc}: expected {expect_val=!r}:{type(t.expect_val).__name__}') + + ok = logloc.replace(' clean_val', '\n\tclean_val' + ).replace(' read_back_val', '\n\tread_back_val' + ).replace('=', '=\t' + ) + output = f'\nok: {ok}' + outputs.append(output) + print(output) + + except Exception as e: + raise RuntimeError(f'Error while testing UPP {upp_fname} {test_idx=}: {e}') from e + + output = '\n'.join(outputs) + '\n' + xo_name = 'test_configurable_parameters' + if update_expected_output: + with resources.path(xo, xo_name) as xo_path: + with open(xo_path, 'w', encoding='utf-8') as f: + f.write(output) + else: + xo_str = resources.read_text(xo, xo_name) + if xo_str != output: + at = 0 + while at < len(output): + if output[at] == xo_str[at]: + at += 1 + continue + break + + raise RuntimeError(f'output differs from expected output at position {at}: "{output[at:at+20]}" != "{xo_str[at:at+20]}"') + + +if __name__ == "__main__": + if '-u' in sys.argv: + update_expected_output = True + sys.argv.remove('-u') + unittest.main() diff --git a/tests/unittests/xo/test_configurable_parameters b/tests/unittests/xo/test_configurable_parameters new file mode 100644 index 00000000..5fd2e7dd --- /dev/null +++ b/tests/unittests/xo/test_configurable_parameters @@ -0,0 +1,336 @@ + +ok: TS48v5_SAIP2.1A_NoBERTLV.der Imsi(val= '123456':str) + clean_val= '123456':str + read_back_val= {'IMSI': '123456', 'IMSI-ACC': '0040'}:{str, hexstr} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der Imsi(val= 123456:int) + clean_val= '123456':str + read_back_val= {'IMSI': '123456', 'IMSI-ACC': '0040'}:{str, hexstr} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der Imsi(val= '123456789012345':str) + clean_val= '123456789012345':str + read_back_val= {'IMSI': '123456789012345', 'IMSI-ACC': '0020'}:{str, hexstr} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der Imsi(val= 123456789012345:int) + clean_val= '123456789012345':str + read_back_val= {'IMSI': '123456789012345', 'IMSI-ACC': '0020'}:{str, hexstr} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der Puk1(val= '12345678':str) + clean_val= b'12345678':bytearray + read_back_val= {'PUK1': '12345678'}:{str} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der Puk2(val= '12345678':str) + clean_val= b'12345678':bytearray + read_back_val= {'PUK2': '12345678'}:{str} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der Pin1(val= '1234':str) + clean_val= b'1234\xff\xff\xff\xff':bytearray + read_back_val= {'PIN1': '1234'}:{str} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der Pin1(val= '123456':str) + clean_val= b'123456\xff\xff':bytearray + read_back_val= {'PIN1': '123456'}:{str} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der Pin1(val= '12345678':str) + clean_val= b'12345678':bytearray + read_back_val= {'PIN1': '12345678'}:{str} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der Adm1(val= '1234':str) + clean_val= b'1234\xff\xff\xff\xff':bytearray + read_back_val= {'ADM1': '1234'}:{str} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der Adm1(val= '123456':str) + clean_val= b'123456\xff\xff':bytearray + read_back_val= {'ADM1': '123456'}:{str} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der Adm1(val= '12345678':str) + clean_val= b'12345678':bytearray + read_back_val= {'ADM1': '12345678'}:{str} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der AlgorithmID(val= 'Milenage':str) + clean_val= 1:int + read_back_val= {'Algorithm': 'Milenage'}:{str} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der AlgorithmID(val= 'TUAK':str) + clean_val= 2:int + read_back_val= {'Algorithm': 'TUAK'}:{str} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der AlgorithmID(val= 'usim-test':str) + clean_val= 3:int + read_back_val= {'Algorithm': 'usim-test'}:{str} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der K(val= '01020304050607080910111213141516':str) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'K': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der K(val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'K': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der K(val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytearray) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'K': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der Opc(val= '01020304050607080910111213141516':str) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'OPc': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der Opc(val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'OPc': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.1A_NoBERTLV.der Opc(val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytearray) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'OPc': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der Imsi(val= '123456':str) + clean_val= '123456':str + read_back_val= {'IMSI': '123456', 'IMSI-ACC': '0040'}:{str, hexstr} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der Imsi(val= 123456:int) + clean_val= '123456':str + read_back_val= {'IMSI': '123456', 'IMSI-ACC': '0040'}:{str, hexstr} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der Imsi(val= '123456789012345':str) + clean_val= '123456789012345':str + read_back_val= {'IMSI': '123456789012345', 'IMSI-ACC': '0020'}:{str, hexstr} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der Imsi(val= 123456789012345:int) + clean_val= '123456789012345':str + read_back_val= {'IMSI': '123456789012345', 'IMSI-ACC': '0020'}:{str, hexstr} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der Puk1(val= '12345678':str) + clean_val= b'12345678':bytearray + read_back_val= {'PUK1': '12345678'}:{str} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der Puk2(val= '12345678':str) + clean_val= b'12345678':bytearray + read_back_val= {'PUK2': '12345678'}:{str} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der Pin1(val= '1234':str) + clean_val= b'1234\xff\xff\xff\xff':bytearray + read_back_val= {'PIN1': '1234'}:{str} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der Pin1(val= '123456':str) + clean_val= b'123456\xff\xff':bytearray + read_back_val= {'PIN1': '123456'}:{str} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der Pin1(val= '12345678':str) + clean_val= b'12345678':bytearray + read_back_val= {'PIN1': '12345678'}:{str} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der Adm1(val= '1234':str) + clean_val= b'1234\xff\xff\xff\xff':bytearray + read_back_val= {'ADM1': '1234'}:{str} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der Adm1(val= '123456':str) + clean_val= b'123456\xff\xff':bytearray + read_back_val= {'ADM1': '123456'}:{str} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der Adm1(val= '12345678':str) + clean_val= b'12345678':bytearray + read_back_val= {'ADM1': '12345678'}:{str} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der AlgorithmID(val= 'Milenage':str) + clean_val= 1:int + read_back_val= {'Algorithm': 'Milenage'}:{str} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der AlgorithmID(val= 'TUAK':str) + clean_val= 2:int + read_back_val= {'Algorithm': 'TUAK'}:{str} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der AlgorithmID(val= 'usim-test':str) + clean_val= 3:int + read_back_val= {'Algorithm': 'usim-test'}:{str} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der K(val= '01020304050607080910111213141516':str) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'K': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der K(val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'K': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der K(val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytearray) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'K': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der Opc(val= '01020304050607080910111213141516':str) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'OPc': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der Opc(val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'OPc': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.3_BERTLV_SUCI.der Opc(val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytearray) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'OPc': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der Imsi(val= '123456':str) + clean_val= '123456':str + read_back_val= {'IMSI': '123456', 'IMSI-ACC': '0040'}:{str, hexstr} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der Imsi(val= 123456:int) + clean_val= '123456':str + read_back_val= {'IMSI': '123456', 'IMSI-ACC': '0040'}:{str, hexstr} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der Imsi(val= '123456789012345':str) + clean_val= '123456789012345':str + read_back_val= {'IMSI': '123456789012345', 'IMSI-ACC': '0020'}:{str, hexstr} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der Imsi(val= 123456789012345:int) + clean_val= '123456789012345':str + read_back_val= {'IMSI': '123456789012345', 'IMSI-ACC': '0020'}:{str, hexstr} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der Puk1(val= '12345678':str) + clean_val= b'12345678':bytearray + read_back_val= {'PUK1': '12345678'}:{str} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der Puk2(val= '12345678':str) + clean_val= b'12345678':bytearray + read_back_val= {'PUK2': '12345678'}:{str} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der Pin1(val= '1234':str) + clean_val= b'1234\xff\xff\xff\xff':bytearray + read_back_val= {'PIN1': '1234'}:{str} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der Pin1(val= '123456':str) + clean_val= b'123456\xff\xff':bytearray + read_back_val= {'PIN1': '123456'}:{str} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der Pin1(val= '12345678':str) + clean_val= b'12345678':bytearray + read_back_val= {'PIN1': '12345678'}:{str} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der Adm1(val= '1234':str) + clean_val= b'1234\xff\xff\xff\xff':bytearray + read_back_val= {'ADM1': '1234'}:{str} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der Adm1(val= '123456':str) + clean_val= b'123456\xff\xff':bytearray + read_back_val= {'ADM1': '123456'}:{str} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der Adm1(val= '12345678':str) + clean_val= b'12345678':bytearray + read_back_val= {'ADM1': '12345678'}:{str} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der AlgorithmID(val= 'Milenage':str) + clean_val= 1:int + read_back_val= {'Algorithm': 'Milenage'}:{str} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der AlgorithmID(val= 'TUAK':str) + clean_val= 2:int + read_back_val= {'Algorithm': 'TUAK'}:{str} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der AlgorithmID(val= 'usim-test':str) + clean_val= 3:int + read_back_val= {'Algorithm': 'usim-test'}:{str} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der K(val= '01020304050607080910111213141516':str) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'K': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der K(val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'K': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der K(val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytearray) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'K': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der Opc(val= '01020304050607080910111213141516':str) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'OPc': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der Opc(val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'OPc': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.1B_NoBERTLV.der Opc(val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytearray) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'OPc': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.3_NoBERTLV.der Imsi(val= '123456':str) + clean_val= '123456':str + read_back_val= {'IMSI': '123456', 'IMSI-ACC': '0040'}:{str, hexstr} + +ok: TS48v5_SAIP2.3_NoBERTLV.der Imsi(val= 123456:int) + clean_val= '123456':str + read_back_val= {'IMSI': '123456', 'IMSI-ACC': '0040'}:{str, hexstr} + +ok: TS48v5_SAIP2.3_NoBERTLV.der Imsi(val= '123456789012345':str) + clean_val= '123456789012345':str + read_back_val= {'IMSI': '123456789012345', 'IMSI-ACC': '0020'}:{str, hexstr} + +ok: TS48v5_SAIP2.3_NoBERTLV.der Imsi(val= 123456789012345:int) + clean_val= '123456789012345':str + read_back_val= {'IMSI': '123456789012345', 'IMSI-ACC': '0020'}:{str, hexstr} + +ok: TS48v5_SAIP2.3_NoBERTLV.der Puk1(val= '12345678':str) + clean_val= b'12345678':bytearray + read_back_val= {'PUK1': '12345678'}:{str} + +ok: TS48v5_SAIP2.3_NoBERTLV.der Puk2(val= '12345678':str) + clean_val= b'12345678':bytearray + read_back_val= {'PUK2': '12345678'}:{str} + +ok: TS48v5_SAIP2.3_NoBERTLV.der Pin1(val= '1234':str) + clean_val= b'1234\xff\xff\xff\xff':bytearray + read_back_val= {'PIN1': '1234'}:{str} + +ok: TS48v5_SAIP2.3_NoBERTLV.der Pin1(val= '123456':str) + clean_val= b'123456\xff\xff':bytearray + read_back_val= {'PIN1': '123456'}:{str} + +ok: TS48v5_SAIP2.3_NoBERTLV.der Pin1(val= '12345678':str) + clean_val= b'12345678':bytearray + read_back_val= {'PIN1': '12345678'}:{str} + +ok: TS48v5_SAIP2.3_NoBERTLV.der Adm1(val= '1234':str) + clean_val= b'1234\xff\xff\xff\xff':bytearray + read_back_val= {'ADM1': '1234'}:{str} + +ok: TS48v5_SAIP2.3_NoBERTLV.der Adm1(val= '123456':str) + clean_val= b'123456\xff\xff':bytearray + read_back_val= {'ADM1': '123456'}:{str} + +ok: TS48v5_SAIP2.3_NoBERTLV.der Adm1(val= '12345678':str) + clean_val= b'12345678':bytearray + read_back_val= {'ADM1': '12345678'}:{str} + +ok: TS48v5_SAIP2.3_NoBERTLV.der AlgorithmID(val= 'Milenage':str) + clean_val= 1:int + read_back_val= {'Algorithm': 'Milenage'}:{str} + +ok: TS48v5_SAIP2.3_NoBERTLV.der AlgorithmID(val= 'TUAK':str) + clean_val= 2:int + read_back_val= {'Algorithm': 'TUAK'}:{str} + +ok: TS48v5_SAIP2.3_NoBERTLV.der AlgorithmID(val= 'usim-test':str) + clean_val= 3:int + read_back_val= {'Algorithm': 'usim-test'}:{str} + +ok: TS48v5_SAIP2.3_NoBERTLV.der K(val= '01020304050607080910111213141516':str) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'K': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.3_NoBERTLV.der K(val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'K': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.3_NoBERTLV.der K(val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytearray) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'K': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.3_NoBERTLV.der Opc(val= '01020304050607080910111213141516':str) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'OPc': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.3_NoBERTLV.der Opc(val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'OPc': '01020304050607080910111213141516'}:{hexstr} + +ok: TS48v5_SAIP2.3_NoBERTLV.der Opc(val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytearray) + clean_val= b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes + read_back_val= {'OPc': '01020304050607080910111213141516'}:{hexstr}