forked from public/pysim
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9c77e4ed94 | |||
| ab19049d19 | |||
| 25e43e1540 | |||
| 6e10da4c55 |
+1
-1
@@ -117,7 +117,7 @@ class Tracer:
|
||||
try:
|
||||
apdu = self.source.read()
|
||||
apdu_counter = apdu_counter + 1
|
||||
except StopIteration:
|
||||
except (StopIteration, KeyboardInterrupt):
|
||||
print("%i APDUs parsed, stop iteration." % apdu_counter)
|
||||
return 0
|
||||
|
||||
|
||||
+49
-38
@@ -300,6 +300,51 @@ class ADF_ARAM(CardADF):
|
||||
'major': v_major, 'minor': v_minor, 'patch': v_patch}}])
|
||||
return ADF_ARAM.xceive_apdu_tlv(scc, '80cadf21', cmd_do, ResponseAramConfigDO)
|
||||
|
||||
@staticmethod
|
||||
def store_ref_ar_do(scc, aid:Hexstr, aid_empty:bool, device_app_id:Hexstr, pkg_ref:str,
|
||||
apdu_filter:Hexstr, apdu_never:bool, apdu_always:bool,
|
||||
nfc_always:bool, nfc_never:bool, android_permissions:Hexstr):
|
||||
# REF
|
||||
ref_do_content = []
|
||||
if aid is not None:
|
||||
ref_do_content += [{'aid_ref_do': aid}]
|
||||
elif aid_empty:
|
||||
ref_do_content += [{'aid_ref_empty_do': None}]
|
||||
ref_do_content += [{'dev_app_id_ref_do': device_app_id}]
|
||||
if pkg_ref:
|
||||
ref_do_content += [{'pkg_ref_do': {'package_name_string': pkg_ref}}]
|
||||
# AR
|
||||
ar_do_content = []
|
||||
if apdu_never:
|
||||
ar_do_content += [{'apdu_ar_do': {'generic_access_rule': 'never'}}]
|
||||
elif apdu_always:
|
||||
ar_do_content += [{'apdu_ar_do': {'generic_access_rule': 'always'}}]
|
||||
elif apdu_filter:
|
||||
if len(apdu_filter) % 16:
|
||||
raise ValueError(f'Invalid non-modulo-16 length of APDU filter: {len(apdu_filter)}')
|
||||
offset = 0
|
||||
apdu_filter_list = []
|
||||
while offset < len(apdu_filter):
|
||||
apdu_filter_list += [{'header': apdu_filter[offset:offset+8],
|
||||
'mask': apdu_filter[offset+8:offset+16]}]
|
||||
offset += 16 # Move offset to the beginning of the next apdu_filter object
|
||||
ar_do_content += [{'apdu_ar_do': {'apdu_filter': apdu_filter_list}}]
|
||||
if nfc_never:
|
||||
ar_do_content += [{'nfc_ar_do': {'nfc_event_access_rule': 'never'}}]
|
||||
elif nfc_always:
|
||||
ar_do_content += [{'nfc_ar_do': {'nfc_event_access_rule': 'always'}}]
|
||||
if android_permissions:
|
||||
ar_do_content += [{'perm_ar_do': {'permissions': android_permissions}}]
|
||||
d = [{'ref_ar_do': [{'ref_do': ref_do_content}, {'ar_do': ar_do_content}]}]
|
||||
csrado = CommandStoreRefArDO()
|
||||
csrado.from_val_dict(d)
|
||||
return ADF_ARAM.store_data(scc, csrado)
|
||||
|
||||
@staticmethod
|
||||
def aram_delete_all(scc):
|
||||
deldo = CommandDelete()
|
||||
return ADF_ARAM.store_data(scc, deldo)
|
||||
|
||||
@with_default_category('Application-Specific Commands')
|
||||
class AddlShellCommands(CommandSet):
|
||||
def do_aram_get_all(self, _opts):
|
||||
@@ -344,48 +389,15 @@ class ADF_ARAM(CardADF):
|
||||
@cmd2.with_argparser(store_ref_ar_do_parse)
|
||||
def do_aram_store_ref_ar_do(self, opts):
|
||||
"""Perform STORE DATA [Command-Store-REF-AR-DO] to store a (new) access rule."""
|
||||
# REF
|
||||
ref_do_content = []
|
||||
if opts.aid is not None:
|
||||
ref_do_content += [{'aid_ref_do': opts.aid}]
|
||||
elif opts.aid_empty:
|
||||
ref_do_content += [{'aid_ref_empty_do': None}]
|
||||
ref_do_content += [{'dev_app_id_ref_do': opts.device_app_id}]
|
||||
if opts.pkg_ref:
|
||||
ref_do_content += [{'pkg_ref_do': {'package_name_string': opts.pkg_ref}}]
|
||||
# AR
|
||||
ar_do_content = []
|
||||
if opts.apdu_never:
|
||||
ar_do_content += [{'apdu_ar_do': {'generic_access_rule': 'never'}}]
|
||||
elif opts.apdu_always:
|
||||
ar_do_content += [{'apdu_ar_do': {'generic_access_rule': 'always'}}]
|
||||
elif opts.apdu_filter:
|
||||
if len(opts.apdu_filter) % 16:
|
||||
raise ValueError(f'Invalid non-modulo-16 length of APDU filter: {len(opts.apdu_filter)}')
|
||||
offset = 0
|
||||
apdu_filter = []
|
||||
while offset < len(opts.apdu_filter):
|
||||
apdu_filter += [{'header': opts.apdu_filter[offset:offset+8],
|
||||
'mask': opts.apdu_filter[offset+8:offset+16]}]
|
||||
offset += 16 # Move offset to the beginning of the next apdu_filter object
|
||||
ar_do_content += [{'apdu_ar_do': {'apdu_filter': apdu_filter}}]
|
||||
if opts.nfc_always:
|
||||
ar_do_content += [{'nfc_ar_do': {'nfc_event_access_rule': 'always'}}]
|
||||
elif opts.nfc_never:
|
||||
ar_do_content += [{'nfc_ar_do': {'nfc_event_access_rule': 'never'}}]
|
||||
if opts.android_permissions:
|
||||
ar_do_content += [{'perm_ar_do': {'permissions': opts.android_permissions}}]
|
||||
d = [{'ref_ar_do': [{'ref_do': ref_do_content}, {'ar_do': ar_do_content}]}]
|
||||
csrado = CommandStoreRefArDO()
|
||||
csrado.from_val_dict(d)
|
||||
res_do = ADF_ARAM.store_data(self._cmd.lchan.scc, csrado)
|
||||
res_do = ADF_ARAM.store_ref_ar_do(self._cmd.lchan.scc, opts.aid, opts.aid_empty, opts.device_app_id,
|
||||
opts.pkg_ref, opts.apdu_filter, opts.apdu_never, opts.apdu_always,
|
||||
opts.nfc_always, opts.nfc_never, opts.android_permissions)
|
||||
if res_do:
|
||||
self._cmd.poutput_json(res_do.to_dict())
|
||||
|
||||
def do_aram_delete_all(self, _opts):
|
||||
"""Perform STORE DATA [Command-Delete[all]] to delete all access rules."""
|
||||
deldo = CommandDelete()
|
||||
res_do = ADF_ARAM.store_data(self._cmd.lchan.scc, deldo)
|
||||
res_do = ADF_ARAM.aram_delete_all(self._cmd.lchan.scc)
|
||||
if res_do:
|
||||
self._cmd.poutput_json(res_do.to_dict())
|
||||
|
||||
@@ -394,7 +406,6 @@ class ADF_ARAM(CardADF):
|
||||
(Proprietary feature that is specific to sysmocom's fork of Bertrand Martel’s ARA-M implementation.)"""
|
||||
self._cmd.lchan.scc.send_apdu_checksw('80e2900001A1', '9000')
|
||||
|
||||
|
||||
# SEAC v1.1 Section 4.1.2.2 + 5.1.2.2
|
||||
sw_aram = {
|
||||
'ARA-M': {
|
||||
|
||||
@@ -21,9 +21,11 @@ import io
|
||||
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 @@ class SmspTpScAddr(ConfigurableParameter):
|
||||
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"""
|
||||
|
||||
+9
-1
@@ -285,6 +285,14 @@ class EF_SUCI_Calc_Info(TransparentEF):
|
||||
{"hnet_pubkey_identifier": 11, "hnet_pubkey":
|
||||
h2b("d1bc365f4997d17ce4374e72181431cbfeba9e1b98d7618f79d48561b144672a")}]} ),
|
||||
]
|
||||
_test_decode = [
|
||||
( 'A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',
|
||||
{"prot_scheme_id_list": [],
|
||||
"hnet_pubkey_list": []} ),
|
||||
( 'A000A100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',
|
||||
{"prot_scheme_id_list": [],
|
||||
"hnet_pubkey_list": []} ),
|
||||
]
|
||||
# 3GPP TS 31.102 Section 4.4.11.8
|
||||
class ProtSchemeIdList(BER_TLV_IE, tag=0xa0):
|
||||
# FIXME: 3GPP TS 24.501 Protection Scheme Identifier
|
||||
@@ -389,7 +397,7 @@ class EF_SUCI_Calc_Info(TransparentEF):
|
||||
# remaining data holds Home Network Public Key Data Object
|
||||
hpkl = EF_SUCI_Calc_Info.HnetPubkeyList()
|
||||
hpkl.from_tlv(in_bytes[pos:])
|
||||
hnet_pubkey_list = self._compact_pubkey_list(hpkl.to_dict()['hnet_pubkey_list'])
|
||||
hnet_pubkey_list = self._compact_pubkey_list(hpkl.to_dict()['hnet_pubkey_list'] or [])
|
||||
|
||||
return {
|
||||
'prot_scheme_id_list': prot_scheme_id_list,
|
||||
|
||||
@@ -267,6 +267,15 @@ class ConfigurableParameterTest(unittest.TestCase):
|
||||
'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 (
|
||||
|
||||
@@ -163,6 +163,14 @@ ok: TS48v5_SAIP2.1A_NoBERTLV.der MilenageXoringConstants(val= b'\xaa\xaa\xaa\xaa
|
||||
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 @@ ok: TS48v5_SAIP2.3_BERTLV_SUCI.der MilenageXoringConstants(val= b'\xaa\xaa\xaa\x
|
||||
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 @@ ok: TS48v5_SAIP2.1B_NoBERTLV.der MilenageXoringConstants(val= b'\xaa\xaa\xaa\xaa
|
||||
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 @@ ok: TS48v5_SAIP2.3_NoBERTLV.der MilenageXoringConstants(val= b'\xaa\xaa\xaa\xaa\
|
||||
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}
|
||||
|
||||
Reference in New Issue
Block a user