From 40e795a82523ab31a92965423497240f56968cc1 Mon Sep 17 00:00:00 2001 From: Philipp Maier Date: Mon, 31 Mar 2025 12:22:21 +0200 Subject: [PATCH] saip-tool: add ProfileElement class for application PE The application profile element has no ProfileElement class yet, so let's create a ProfileElementApplication class and move the existing extract-apps code into a method of ProfileElementApplication. Change-Id: Iaa43036d388fbf1714c53cab1fc21092c4667a21 --- contrib/saip-tool.py | 11 +---------- pySim/esim/saip/__init__.py | 26 +++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/contrib/saip-tool.py b/contrib/saip-tool.py index 64aba933..4747ab97 100755 --- a/contrib/saip-tool.py +++ b/contrib/saip-tool.py @@ -19,14 +19,12 @@ import os import sys import argparse import logging -import zipfile from pathlib import Path as PlPath from typing import List from osmocom.utils import h2b, b2h, swap_nibbles from pySim.esim.saip import * from pySim.esim.saip.validation import CheckBasicStructure -from pySim import javacard from pySim.pprint import HexBytesPrettyPrinter pp = HexBytesPrettyPrinter(indent=4,width=500) @@ -231,16 +229,9 @@ def do_extract_apps(pes:ProfileElementSequence, opts): apps = pes.pe_by_type.get('application', []) for app_pe in apps: package_aid = b2h(app_pe.decoded['loadBlock']['loadPackageAID']) - fname = os.path.join(opts.output_dir, '%s-%s.%s' % (pes.iccid, package_aid, opts.format)) - load_block_obj = app_pe.decoded['loadBlock']['loadBlockObject'] print("Writing Load Package AID: %s to file %s" % (package_aid, fname)) - if opts.format == 'ijc': - with open(fname, 'wb') as f: - f.write(load_block_obj) - else: - with io.BytesIO(load_block_obj) as f, zipfile.ZipFile(fname, 'w') as z: - javacard.ijc_to_cap(f, z, package_aid) + app_pe.to_file(fname) def do_tree(pes:ProfileElementSequence, opts): pes.mf.print_tree() diff --git a/pySim/esim/saip/__init__.py b/pySim/esim/saip/__init__.py index 64ea7cb6..d6b41ba8 100644 --- a/pySim/esim/saip/__init__.py +++ b/pySim/esim/saip/__init__.py @@ -22,6 +22,8 @@ import os from typing import Tuple, List, Optional, Dict, Union from collections import OrderedDict import asn1tools +import zipfile +from pySim import javacard from osmocom.utils import b2h, h2b, Hexstr from osmocom.tlv import BER_TLV_IE, bertlv_parse_tag, bertlv_parse_len from osmocom.construct import build_construct, parse_construct, GreedyInteger @@ -506,7 +508,7 @@ class ProfileElement: # TODO: cdmaParameter 'securityDomain': ProfileElementSD, 'rfm': ProfileElementRFM, - # TODO: application + 'application': ProfileElementApplication, # TODO: nonStandard 'end': ProfileElementEnd, 'mf': ProfileElementMF, @@ -1087,6 +1089,28 @@ class ProfileElementSSD(ProfileElementSD): 'uiccToolkitApplicationSpecificParametersField': h2b('01000001000000020112036C756500'), } +class ProfileElementApplication(ProfileElement): + """Class representing an application ProfileElement.""" + type = 'application' + + def __init__(self, decoded: Optional[dict] = None, **kwargs): + super().__init__(decoded, **kwargs) + + def to_file(self, filename:str): + """Write loadBlockObject contents of application ProfileElement to a .cap or .ijc file.""" + + load_package_aid = b2h(self.decoded['loadBlock']['loadPackageAID']) + load_block_object = self.decoded['loadBlock']['loadBlockObject'] + + if filename.lower().endswith('.cap'): + with io.BytesIO(load_block_object) as f, zipfile.ZipFile(filename, 'w') as z: + javacard.ijc_to_cap(f, z, load_package_aid) + elif filename.lower().endswith('.ijc'): + with open(filename, 'wb') as f: + f.write(load_block_object) + else: + raise ValueError('Invalid file type, file must either .cap or .ijc') + class ProfileElementRFM(ProfileElement): type = 'rfm'