laforge submitted this change.
saip/personalization: add MncLen configurable parameter
Add a new ConfigurableParameter that represents the MNC length
(2 or 3 digits) in EF.AD (Administrative Data).
Change-Id: I6c600faeab00ffb072acbe94c9a8b2d1397c07d3
Co-authored-by: Vadim Yanitskiy <vyanitskiy@sysmocom.de>
Jenkins: skip-card-test
---
M pySim/esim/saip/personalization.py
M tests/unittests/test_configurable_parameters.py
M tests/unittests/xo/test_configurable_parameters
3 files changed, 109 insertions(+), 0 deletions(-)
diff --git a/pySim/esim/saip/personalization.py b/pySim/esim/saip/personalization.py
index efde37a..a73678f 100644
--- a/pySim/esim/saip/personalization.py
+++ b/pySim/esim/saip/personalization.py
@@ -21,9 +21,11 @@
import re
from typing import List, Tuple, Generator, Optional
+from construct.core import StreamError
from osmocom.tlv import camel_to_snake
from osmocom.utils import hexstr
from pySim.utils import enc_iccid, dec_iccid, enc_imsi, dec_imsi, h2b, b2h, rpad, sanitize_iccid
+from pySim.ts_31_102 import EF_AD
from pySim.ts_51_011 import EF_SMSP
from pySim.esim.saip import param_source
from pySim.esim.saip import ProfileElement, ProfileElementSD, ProfileElementSequence
@@ -660,6 +662,72 @@
yield { cls.name: cls.tuple_to_str((international, digits)) }
+class MncLen(EnumParam):
+ """MNC length. Sets only the MNC length field in EF.AD (Administrative Data).
+ Accepted values: integer 2 or 3, digit strings '2' or '3', or enum names 'MNC2'/'MNC3'.
+ """
+ name = 'MNC-LEN'
+ example_input = '2'
+ default_source = param_source.ConstantSource
+
+ class Values(enum.IntEnum):
+ MNC2 = 2
+ MNC3 = 3
+
+ @classmethod
+ def validate_val(cls, val):
+ if isinstance(val, str) and val.isdigit():
+ val = int(val)
+ return super().validate_val(val)
+
+ @classmethod
+ def _get_f_ad(cls, pe: ProfileElement):
+ if not hasattr(pe, 'files'):
+ return None
+ f_ad = pe.files.get('ef-ad', None)
+ if f_ad and f_ad.body:
+ return f_ad
+ return None
+
+ @classmethod
+ def _decode_f_ad(cls, f_ad):
+ try:
+ ef_ad_dec = EF_AD().decode_bin(f_ad.body)
+ except StreamError:
+ return None
+ if 'mnc_len' not in ef_ad_dec:
+ return None
+ return ef_ad_dec
+
+ @classmethod
+ def apply_val(cls, pes: ProfileElementSequence, val: int):
+ for pe in pes.get_pes_for_type('usim'):
+ f_ad = cls._get_f_ad(pe)
+ if f_ad is None:
+ continue
+ # decode existing values
+ ef_ad_dec = cls._decode_f_ad(f_ad)
+ if ef_ad_dec is None:
+ continue
+ # change mnc_len
+ ef_ad_dec['mnc_len'] = val
+ # re-encode into the File body
+ f_ad.body = EF_AD().encode_bin(ef_ad_dec)
+ pe.file2pe(f_ad)
+
+ @classmethod
+ def get_values_from_pes(cls, pes: ProfileElementSequence):
+ for pe in pes.get_pes_for_type('usim'):
+ f_ad = cls._get_f_ad(pe)
+ if f_ad is None:
+ continue
+ ef_ad_dec = cls._decode_f_ad(f_ad)
+ if ef_ad_dec is None:
+ continue
+ mnc_len = ef_ad_dec.get('mnc_len')
+ yield { cls.name: str(mnc_len) }
+
+
class SdKey(BinaryParam):
"""Configurable Security Domain (SD) Key. Value is presented as bytes.
Non-abstract implementations are generated in SdKey.generate_sd_key_classes"""
diff --git a/tests/unittests/test_configurable_parameters.py b/tests/unittests/test_configurable_parameters.py
index 7f9c8b0..0ffc4b4 100755
--- a/tests/unittests/test_configurable_parameters.py
+++ b/tests/unittests/test_configurable_parameters.py
@@ -267,6 +267,15 @@
'11111111111111111111111111111111'
'22222222222222222222222222222222'),
+ Paramtest(param_cls=p13n.MncLen,
+ val='2',
+ expect_clean_val=2,
+ expect_val='2'),
+ Paramtest(param_cls=p13n.MncLen,
+ val=3,
+ expect_clean_val=3,
+ expect_val='3'),
+
]
for sdkey_cls in (
diff --git a/tests/unittests/xo/test_configurable_parameters b/tests/unittests/xo/test_configurable_parameters
index d64e7ba..9ab6073 100644
--- a/tests/unittests/xo/test_configurable_parameters
+++ b/tests/unittests/xo/test_configurable_parameters
@@ -163,6 +163,14 @@
clean_val= b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11""""""""""""""""':bytes
read_back_val= {'MilenageXOR': 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccc1111111111111111111111111111111122222222222222222222222222222222'}:{hexstr}
+ok: TS48v5_SAIP2.1A_NoBERTLV.der MncLen(val= '2':str)
+ clean_val= 2:int
+ read_back_val= {'MNC-LEN': '2'}:{str}
+
+ok: TS48v5_SAIP2.1A_NoBERTLV.der MncLen(val= 3:int)
+ clean_val= 3:int
+ read_back_val= {'MNC-LEN': '3'}:{str}
+
ok: TS48v5_SAIP2.1A_NoBERTLV.der SdKeyScp02Kvn20AesDek(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= {'SCP02-KVN20-AES-DEK': '01020304050607080910111213141516'}:{hexstr}
@@ -855,6 +863,14 @@
clean_val= b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11""""""""""""""""':bytes
read_back_val= {'MilenageXOR': 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccc1111111111111111111111111111111122222222222222222222222222222222'}:{hexstr}
+ok: TS48v5_SAIP2.3_BERTLV_SUCI.der MncLen(val= '2':str)
+ clean_val= 2:int
+ read_back_val= {'MNC-LEN': '2'}:{str}
+
+ok: TS48v5_SAIP2.3_BERTLV_SUCI.der MncLen(val= 3:int)
+ clean_val= 3:int
+ read_back_val= {'MNC-LEN': '3'}:{str}
+
ok: TS48v5_SAIP2.3_BERTLV_SUCI.der SdKeyScp02Kvn20AesDek(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= {'SCP02-KVN20-AES-DEK': '01020304050607080910111213141516'}:{hexstr}
@@ -1547,6 +1563,14 @@
clean_val= b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11""""""""""""""""':bytes
read_back_val= {'MilenageXOR': 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccc1111111111111111111111111111111122222222222222222222222222222222'}:{hexstr}
+ok: TS48v5_SAIP2.1B_NoBERTLV.der MncLen(val= '2':str)
+ clean_val= 2:int
+ read_back_val= {'MNC-LEN': '2'}:{str}
+
+ok: TS48v5_SAIP2.1B_NoBERTLV.der MncLen(val= 3:int)
+ clean_val= 3:int
+ read_back_val= {'MNC-LEN': '3'}:{str}
+
ok: TS48v5_SAIP2.1B_NoBERTLV.der SdKeyScp02Kvn20AesDek(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= {'SCP02-KVN20-AES-DEK': '01020304050607080910111213141516'}:{hexstr}
@@ -2239,6 +2263,14 @@
clean_val= b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11""""""""""""""""':bytes
read_back_val= {'MilenageXOR': 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccc1111111111111111111111111111111122222222222222222222222222222222'}:{hexstr}
+ok: TS48v5_SAIP2.3_NoBERTLV.der MncLen(val= '2':str)
+ clean_val= 2:int
+ read_back_val= {'MNC-LEN': '2'}:{str}
+
+ok: TS48v5_SAIP2.3_NoBERTLV.der MncLen(val= 3:int)
+ clean_val= 3:int
+ read_back_val= {'MNC-LEN': '3'}:{str}
+
ok: TS48v5_SAIP2.3_NoBERTLV.der SdKeyScp02Kvn20AesDek(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= {'SCP02-KVN20-AES-DEK': '01020304050607080910111213141516'}:{hexstr}
To view, visit change 42672. To unsubscribe, or for help writing mail filters, visit settings.