laforge has submitted this change. (
https://gerrit.osmocom.org/c/pysim/+/37169?usp=email
)
Change subject: saip-tool: Add 'extract-apps' to dump all applications from eSIM
profile
......................................................................
saip-tool: Add 'extract-apps' to dump all applications from eSIM profile
This new action can be used to dump all java applications as either raw
IJC file or converted to CAP format (the usual format generated by
JavaCard toolchains).
Change-Id: I51cffa5ba3ddbea491341d678ec9249d7cf470a5
---
M contrib/saip-tool.py
M pySim/esim/saip/__init__.py
A pySim/javacard.py
3 files changed, 68 insertions(+), 1 deletion(-)
Approvals:
laforge: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/contrib/saip-tool.py b/contrib/saip-tool.py
index 68072fa..6f2a2a4 100755
--- a/contrib/saip-tool.py
+++ b/contrib/saip-tool.py
@@ -19,11 +19,13 @@
import sys
import argparse
import logging
+import zipfile
from pathlib import Path
from typing import List
from pySim.esim.saip import *
from pySim.esim.saip.validation import CheckBasicStructure
+from pySim import javacard
from pySim.utils import h2b, b2h, swap_nibbles
from pySim.pprint import HexBytesPrettyPrinter
@@ -56,6 +58,10 @@
parser_info = subparsers.add_parser('info', help='Display information about
the profile')
+parser_eapp = subparsers.add_parser('extract-apps', help='Extract
applications as loadblock file')
+parser_eapp.add_argument('--output-dir', default='.', help='Output
directory (where to store files)')
+parser_eapp.add_argument('--format', default='cap',
choices=['ijc', 'cap'], help='Data format of output files')
+
def do_split(pes: ProfileElementSequence, opts):
i = 0
for pe in pes.pe_list:
@@ -176,6 +182,21 @@
print("\tInstance AID: %s" % b2h(inst['instanceAID']))
pass
+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)
+
if __name__ == '__main__':
opts = parser.parse_args()
@@ -197,3 +218,5 @@
do_remove_naa(pes, opts)
elif opts.command == 'info':
do_info(pes, opts)
+ elif opts.command == 'extract-apps':
+ do_extract_apps(pes, opts)
diff --git a/pySim/esim/saip/__init__.py b/pySim/esim/saip/__init__.py
index 278b5cf..e690e6c 100644
--- a/pySim/esim/saip/__init__.py
+++ b/pySim/esim/saip/__init__.py
@@ -617,7 +617,19 @@
# TODO: remove any records related to the ADFs from EF.DIR
def __repr__(self) -> str:
- return "PESequence(%s)" % ', '.join([str(x) for x in
self.pe_list])
+ return "PESequence(%s: %s)" % (self.iccid, ', '.join([str(x)
for x in self.pe_list]))
def __iter__(self) -> str:
yield from self.pe_list
+
+ @property
+ def iccid(self) -> Optional[str]:
+ """The ICCID of the profile."""
+ if not 'header' in self.pe_by_type:
+ return None
+ if len(self.pe_by_type['header']) < 1:
+ return None
+ pe_hdr_dec = self.pe_by_type['header'][0].decoded
+ if not 'iccid' in pe_hdr_dec:
+ return None
+ return b2h(pe_hdr_dec['iccid'])
diff --git a/pySim/javacard.py b/pySim/javacard.py
new file mode 100644
index 0000000..46f6ec0
--- /dev/null
+++ b/pySim/javacard.py
@@ -0,0 +1,19 @@
+# JavaCard related utilities
+
+import zipfile
+import struct
+import sys
+import io
+
+def ijc_to_cap(in_file: io.IOBase, out_zip: zipfile.ZipFile, p : str = "foo"):
+ """Convert an ICJ (Interoperable Java Card) file [back] to a CAP
file."""
+ TAGS = ["Header", "Directory", "Applet",
"Import", "ConstantPool", "Class", "Method",
"StaticField", "RefLocation", "Export",
"Descriptor", "Debug"]
+ b = in_file.read()
+ while len(b):
+ tag, size = struct.unpack('!BH', b[0:3])
+ out_zip.writestr(p+"/javacard/"+TAGS[tag-1]+".cap",
b[0:3+size])
+ b = b[3+size:]
+
+# example usage:
+# with io.open(sys.argv[1],"rb") as f, zipfile.ZipFile(sys.argv[2],
"wb") as z:
+# ijc_to_cap(f, z)
--
To view, visit
https://gerrit.osmocom.org/c/pysim/+/37169?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I51cffa5ba3ddbea491341d678ec9249d7cf470a5
Gerrit-Change-Number: 37169
Gerrit-PatchSet: 4
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-MessageType: merged