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
This commit is contained in:
Philipp Maier
2025-03-31 12:22:21 +02:00
parent dc2b9574c9
commit 40e795a825
2 changed files with 26 additions and 11 deletions

View File

@@ -19,14 +19,12 @@ import os
import sys import sys
import argparse import argparse
import logging import logging
import zipfile
from pathlib import Path as PlPath from pathlib import Path as PlPath
from typing import List from typing import List
from osmocom.utils import h2b, b2h, swap_nibbles from osmocom.utils import h2b, b2h, swap_nibbles
from pySim.esim.saip import * from pySim.esim.saip import *
from pySim.esim.saip.validation import CheckBasicStructure from pySim.esim.saip.validation import CheckBasicStructure
from pySim import javacard
from pySim.pprint import HexBytesPrettyPrinter from pySim.pprint import HexBytesPrettyPrinter
pp = HexBytesPrettyPrinter(indent=4,width=500) pp = HexBytesPrettyPrinter(indent=4,width=500)
@@ -231,16 +229,9 @@ def do_extract_apps(pes:ProfileElementSequence, opts):
apps = pes.pe_by_type.get('application', []) apps = pes.pe_by_type.get('application', [])
for app_pe in apps: for app_pe in apps:
package_aid = b2h(app_pe.decoded['loadBlock']['loadPackageAID']) package_aid = b2h(app_pe.decoded['loadBlock']['loadPackageAID'])
fname = os.path.join(opts.output_dir, '%s-%s.%s' % (pes.iccid, package_aid, opts.format)) 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)) print("Writing Load Package AID: %s to file %s" % (package_aid, fname))
if opts.format == 'ijc': app_pe.to_file(fname)
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)
def do_tree(pes:ProfileElementSequence, opts): def do_tree(pes:ProfileElementSequence, opts):
pes.mf.print_tree() pes.mf.print_tree()

View File

@@ -22,6 +22,8 @@ import os
from typing import Tuple, List, Optional, Dict, Union from typing import Tuple, List, Optional, Dict, Union
from collections import OrderedDict from collections import OrderedDict
import asn1tools import asn1tools
import zipfile
from pySim import javacard
from osmocom.utils import b2h, h2b, Hexstr from osmocom.utils import b2h, h2b, Hexstr
from osmocom.tlv import BER_TLV_IE, bertlv_parse_tag, bertlv_parse_len from osmocom.tlv import BER_TLV_IE, bertlv_parse_tag, bertlv_parse_len
from osmocom.construct import build_construct, parse_construct, GreedyInteger from osmocom.construct import build_construct, parse_construct, GreedyInteger
@@ -506,7 +508,7 @@ class ProfileElement:
# TODO: cdmaParameter # TODO: cdmaParameter
'securityDomain': ProfileElementSD, 'securityDomain': ProfileElementSD,
'rfm': ProfileElementRFM, 'rfm': ProfileElementRFM,
# TODO: application 'application': ProfileElementApplication,
# TODO: nonStandard # TODO: nonStandard
'end': ProfileElementEnd, 'end': ProfileElementEnd,
'mf': ProfileElementMF, 'mf': ProfileElementMF,
@@ -1087,6 +1089,28 @@ class ProfileElementSSD(ProfileElementSD):
'uiccToolkitApplicationSpecificParametersField': h2b('01000001000000020112036C756500'), '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): class ProfileElementRFM(ProfileElement):
type = 'rfm' type = 'rfm'