Attention is currently required from: dexter, laforge, osmith.
Hello Jenkins Builder, dexter, osmith,
I'd like you to reexamine a change. Please visit
https://gerrit.osmocom.org/c/pysim/+/36962?usp=email
to look at the new patch set (#4).
The following approvals got outdated and were removed:
Code-Review+1 by osmith
Change subject: document the CardKeyProvider
......................................................................
document the CardKeyProvider
Change-Id: Ie6fc24695dd956a4f9fd6f243d3b0ef66acf877b
---
A docs/card-key-provider.rst
M docs/shell.rst
2 files changed, 112 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/62/36962/4
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/36962?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: Ie6fc24695dd956a4f9fd6f243d3b0ef66acf877b
Gerrit-Change-Number: 36962
Gerrit-PatchSet: 4
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Attention: osmith <osmith(a)sysmocom.de>
Gerrit-Attention: laforge <laforge(a)osmocom.org>
Gerrit-Attention: dexter <pmaier(a)sysmocom.de>
Gerrit-MessageType: newpatchset
Attention is currently required from: dexter, fixeria, laforge, osmith.
Hello Jenkins Builder, dexter, fixeria, osmith,
I'd like you to reexamine a change. Please visit
https://gerrit.osmocom.org/c/pysim/+/36930?usp=email
to look at the new patch set (#6).
The following approvals got outdated and were removed:
Code-Review+1 by fixeria, Code-Review+1 by osmith, Verified+1 by Jenkins Builder
Change subject: CardKeyProvider: Implement support for column-based transport key encryption
......................................................................
CardKeyProvider: Implement support for column-based transport key encryption
It's generally a bad idea to keep [card specific] key material lying
around unencrypted in CSV files. The industry standard solution in the
GSMA is a so-called "transport key", which encrypts the key material.
Let's introduce support for this in the CardKeyProvider (and
specifically, the CardKeyProviderCSV) and allow the user to specify
transport key material as command line options to pySim-shell.
Different transport keys can be used for different key materials, so
allow specification of keys on a CSV-column base.
The higher-level goal is to allow the CSV file not only to store
the ADM keys (like now), but also global platform key material for
establishing SCP towards various security domains in a given card.
Change-Id: I13146a799448d03c681dc868aaa31eb78b7821ff
---
A contrib/csv-encrypt-columns.py
M docs/card-key-provider.rst
M pySim-shell.py
M pySim/card_key_provider.py
4 files changed, 192 insertions(+), 15 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/30/36930/6
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/36930?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: I13146a799448d03c681dc868aaa31eb78b7821ff
Gerrit-Change-Number: 36930
Gerrit-PatchSet: 6
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Attention: osmith <osmith(a)sysmocom.de>
Gerrit-Attention: laforge <laforge(a)osmocom.org>
Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Attention: dexter <pmaier(a)sysmocom.de>
Gerrit-MessageType: newpatchset
Attention is currently required from: laforge, osmith.
Hello Jenkins Builder, osmith,
I'd like you to reexamine a change. Please visit
https://gerrit.osmocom.org/c/pysim/+/36961?usp=email
to look at the new patch set (#5).
The following approvals got outdated and were removed:
Code-Review+1 by osmith
Change subject: pySim.esim.saip: Meaningful constructors for [I]SD + SSD
......................................................................
pySim.esim.saip: Meaningful constructors for [I]SD + SSD
So far the main use case was to read a ProfileElement-SD from
a DER file. But when we want to construct one from scratch,
we need to have the constructor put some meaningful [default]
values into the class members.
Change-Id: I69e104f1d78165c12291317326dbab05977a1574
---
M pySim/esim/saip/__init__.py
1 file changed, 85 insertions(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/61/36961/5
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/36961?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: I69e104f1d78165c12291317326dbab05977a1574
Gerrit-Change-Number: 36961
Gerrit-PatchSet: 5
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Attention: osmith <osmith(a)sysmocom.de>
Gerrit-Attention: laforge <laforge(a)osmocom.org>
Gerrit-MessageType: newpatchset
Attention is currently required from: laforge.
Hello Jenkins Builder,
I'd like you to reexamine a change. Please visit
https://gerrit.osmocom.org/c/pysim/+/37010?usp=email
to look at the new patch set (#2).
The following approvals got outdated and were removed:
Verified-1 by Jenkins Builder
Change subject: esim.saip: Add ProfileElementSequence.remove_naas_of_type
......................................................................
esim.saip: Add ProfileElementSequence.remove_naas_of_type
This method allows the caller to remove all NAAs of a certain type,
for example to remove all CSIM instances from a given profile.
Change-Id: I64438bf0be58bad7a561c3744b7e9b1338a7857c
---
M pySim/esim/saip/__init__.py
M pySim/esim/saip/oid.py
2 files changed, 99 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/10/37010/2
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/37010?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: I64438bf0be58bad7a561c3744b7e9b1338a7857c
Gerrit-Change-Number: 37010
Gerrit-PatchSet: 2
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Attention: laforge <laforge(a)osmocom.org>
Gerrit-MessageType: newpatchset
laforge has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/37010?usp=email )
Change subject: esim.saip: Add ProfileElementSequence.remove_naas_of_type
......................................................................
esim.saip: Add ProfileElementSequence.remove_naas_of_type
This method allows the caller to remove all NAAs of a certain type,
for example to remove all CSIM instances from a given profile.
Change-Id: I64438bf0be58bad7a561c3744b7e9b1338a7857c
---
M pySim/esim/saip/__init__.py
M pySim/esim/saip/oid.py
2 files changed, 98 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/10/37010/1
diff --git a/pySim/esim/saip/__init__.py b/pySim/esim/saip/__init__.py
index 938dc48..4d39b64 100644
--- a/pySim/esim/saip/__init__.py
+++ b/pySim/esim/saip/__init__.py
@@ -27,12 +27,57 @@
from pySim.construct import build_construct
from pySim.esim import compile_asn1_subdir
from pySim.esim.saip import templates
+from pySim.esim.saip import oid
from pySim.tlv import BER_TLV_IE
from pySim.global_platform import KeyType, KeyUsageQualifier
from pySim.global_platform.uicc import UiccSdInstallParams
asn1 = compile_asn1_subdir('saip')
+class Naa:
+ """A class defining a Network Access Application (NAA)."""
+ name = None
+ # AID prefix, as used for ADF and EF.DIR
+ aid = None
+ # the ProfileElement types used specifically in this NAA
+ pe_types = []
+ # we only use the base DN of each OID; there may be subsequent versions underneath it
+ templates = []
+
+ @classmethod
+ def adf_name(cls):
+ return 'adf-' + cls.mandatory_services[0]
+
+class NaaCsim(Naa):
+ name = "csim"
+ aid = h2b("")
+ mandatory_services = ["csim"]
+ pe_types = ["csim", "opt-csim", "cdmaParameter"]
+ templates = [oid.ADF_CSIM_by_default, oid.ADF_CSIM_not_by_default]
+
+class NaaUsim(Naa):
+ name = "usim"
+ aid = h2b("")
+ mandatory_services = ["usim"]
+ pe_types = ["usim", "opt-usim"]
+ templates = [oid.ADF_USIM_by_default, oid.ADF_USIM_not_by_default,
+ oid.DF_PHONEBOOK_ADF_USIM, oid.DF_GSM_ACCESS_ADF_USIM,
+ oid.DF_EAP, oid.DF_5GS, oid.DF_SAIP, oid.DF_SNPN,
+ oid.DF_5GProSe]
+
+class NaaIsim(Naa):
+ name = "isim"
+ aid = h2b("")
+ mandatory_services = ["isim"]
+ pe_types = ["isim", "opt-isim"]
+ templates = [oid.ADF_ISIM_by_default, oid.ADF_ISIM_not_by_default]
+
+NAAs = {
+ NaaCsim.name: NaaCsim,
+ NaaUsim.name: NaaUsim,
+ NaaIsim.name: NaaIsim,
+}
+
class File:
"""Internal representation of a file in a profile filesystem.
@@ -513,6 +558,43 @@
self._process_pelist()
self.renumber_identification()
+ def remove_naas_of_type(self, naa: Naa) -> None:
+ """Remove all instances of NAAs of given type. This can be used, for example,
+ to remove all CSIM NAAs from a profile. Will not just remove the PEs, but also
+ any records in 'eUICC-Mandatory-services' or 'eUICC-Mandatory-GFSTEList'."""
+ hdr = self.pe_by_type['header'][0]
+ # remove any associated mandatory services
+ for service in naa.mandatory_services:
+ if service in hdr.decoded['eUICC-Mandatory-services']:
+ del hdr.decoded['eUICC-Mandatory-services'][service]
+ # remove any associaed mandatory filesystem templates
+ for template in naa.templates:
+ if template in hdr.decoded['eUICC-Mandatory-GFSTEList']:
+ hdr.decoded['eUICC-Mandatory-GFSTEList'] = [x for x in hdr.decoded['eUICC-Mandatory-GFSTEList'] if not template.prefix_match(x)]
+ # determine the ADF names (AIDs) of all NAA ADFs
+ naa_adf_names = []
+ if naa.pe_types[0] in self.pe_by_type:
+ for pe in self.pe_by_type[naa.pe_types[0]]:
+ adf_name = naa.adf_name()
+ adf = File(adf_name, pe.decoded[adf_name])
+ naa_adf_names.append(adf.fileDescriptor['dfName'])
+ # remove PEs of each NAA instance
+ if naa.name in self.pes_by_naa:
+ for inst in self.pes_by_naa[naa.name]:
+ # delete all the PEs of the NAA
+ self.pe_list = [pe for pe in self.pe_list if pe not in inst]
+ self._process_pelist()
+ # remove any RFM PEs for the just-removed ADFs
+ if 'rfm' in self.pe_by_type:
+ to_delete_pes = []
+ for rfm_pe in self.pe_by_type['rfm']:
+ if 'adfRFMAccess' in rfm_pe.decoded:
+ if rfm_pe.decoded['adfRFMAccess']['adfAID'] in naa_adf_names:
+ to_delete_pes.append(rfm_pe)
+ self.pe_list = [pe for pe in self.pe_list if pe not in to_delete_pes]
+ self._process_pelist()
+ # 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])
diff --git a/pySim/esim/saip/oid.py b/pySim/esim/saip/oid.py
index 238e49f..d33b786 100644
--- a/pySim/esim/saip/oid.py
+++ b/pySim/esim/saip/oid.py
@@ -38,6 +38,10 @@
def __repr__(self) -> str:
return 'OID(%s)' % (str(self))
+ def prefix_match(self, oid_str):
+ """determine if oid_str is equal or below our OID."""
+ return oid_str.startswith(str(self))
+
class eOID(OID):
"""OID helper for TCA eUICC prefix"""
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/37010?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: I64438bf0be58bad7a561c3744b7e9b1338a7857c
Gerrit-Change-Number: 37010
Gerrit-PatchSet: 1
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-MessageType: newchange
laforge has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/37011?usp=email )
Change subject: add contrib/saip-tool.py
......................................................................
add contrib/saip-tool.py
This is a tool to work with eSIM profiles in SAIP format. It allows
to dump the contents, run constraint checkers as well as splitting
of the PE-Sequence into the individual PEs.
Change-Id: I396bcd594e0628dfc26bd90233317a77e2f91b20
---
A contrib/saip-tool.py
1 file changed, 176 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/11/37011/1
diff --git a/contrib/saip-tool.py b/contrib/saip-tool.py
new file mode 100755
index 0000000..eae906c
--- /dev/null
+++ b/contrib/saip-tool.py
@@ -0,0 +1,163 @@
+#!/usr/bin/env python3
+
+# (C) 2024 by Harald Welte <laforge(a)osmocom.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import sys
+import argparse
+import logging
+from pathlib import Path
+from typing import List
+
+from pySim.esim.saip import *
+from pySim.esim.saip.validation import CheckBasicStructure
+from pySim.utils import h2b, b2h, swap_nibbles
+from pySim.pprint import HexBytesPrettyPrinter
+
+pp = HexBytesPrettyPrinter(indent=4,width=500)
+
+logging.basicConfig(level=logging.DEBUG)
+
+parser = argparse.ArgumentParser(description="""
+Utility program to work with eSIM SAIP (SimAlliance Interoperable Profile) files.""")
+parser.add_argument('INPUT_UPP', help='Unprotected Profile Package Input file')
+subparsers = parser.add_subparsers(dest='command', help="The command to perform", required=True)
+
+parser_split = subparsers.add_parser('split', help='Split PE-Sequence into individual PEs')
+parser_split.add_argument('--output-prefix', default='.', help='Prefix path/filename for output files')
+
+parser_dump = subparsers.add_parser('dump', help='Dump information on PE-Sequence')
+parser_dump.add_argument('mode', choices=['all_pe', 'all_pe_by_type', 'all_pe_by_naa'])
+parser_dump.add_argument('--dump-decoded', action='store_true', help='Dump decoded PEs')
+
+parser_check = subparsers.add_parser('check', help='Run constraint checkers on PE-Sequence')
+
+parser_rpe = subparsers.add_parser('remove-pe', help='Remove specified PEs from PE-Sequence')
+parser_rpe.add_argument('--output-file', required=True, help='Output file name')
+parser_rpe.add_argument('--identification', type=int, action='append', help='Remove PEs matching specified identification')
+
+parser_rn = subparsers.add_parser('remove-naa', help='Remove speciifed NAAs from PE-Sequence')
+parser_rn.add_argument('--output-file', required=True, help='Output file name')
+parser_rn.add_argument('--naa-type', required=True, choices=NAAs.keys(), help='Network Access Application type to remove')
+# TODO: add an --naa-index or the like, so only one given instance can be removed
+
+
+def do_split(pes: ProfileElementSequence, opts):
+ i = 0
+ for pe in pes.pe_list:
+ basename = Path(opts.INPUT_UPP).stem
+ if not pe.identification:
+ fname = '%s-%02u-%s.der' % (basename, i, pe.type)
+ else:
+ fname = '%s-%02u-%05u-%s.der' % (basename, i, pe.identification, pe.type)
+ print("writing single PE to file '%s'" % fname)
+ with open(os.path.join(opts.output_prefix, fname), 'wb') as outf:
+ outf.write(pe.to_der())
+ i += 1
+
+def do_dump(pes: ProfileElementSequence, opts):
+ def print_all_pe(pes: ProfileElementSequence, dump_decoded:bool = False):
+ # iterate over each pe in the pes (using its __iter__ method)
+ for pe in pes:
+ print("="*70 + " " + pe.type)
+ if dump_decoded:
+ pp.pprint(pe.decoded)
+
+ def print_all_pe_by_type(pes: ProfileElementSequence, dump_decoded:bool = False):
+ # sort by PE type and show all PE within that type
+ for pe_type in pes.pe_by_type.keys():
+ print("="*70 + " " + pe_type)
+ for pe in pes.pe_by_type[pe_type]:
+ pp.pprint(pe)
+ if dump_decoded:
+ pp.pprint(pe.decoded)
+
+ def print_all_pe_by_naa(pes: ProfileElementSequence, dump_decoded:bool = False):
+ for naa in pes.pes_by_naa:
+ i = 0
+ for naa_instance in pes.pes_by_naa[naa]:
+ print("="*70 + " " + naa + str(i))
+ i += 1
+ for pe in naa_instance:
+ pp.pprint(pe.type)
+ if dump_decoded:
+ for d in pe.decoded:
+ print(" %s" % d)
+ #pp.pprint(pe.decoded[d])
+ #if pe.type in ['akaParameter', 'pinCodes', 'pukCodes']:
+ # pp.pprint(pe.decoded)
+
+ if opts.mode == 'all_pe':
+ print_all_pe(pes, opts.dump_decoded)
+ elif opts.mode == 'all_pe_by_type':
+ print_all_pe_by_type(pes, opts.dump_decoded)
+ elif opts.mode == 'all_pe_by_naa':
+ print_all_pe_by_naa(pes, opts.dump_decoded)
+
+def do_check(pes: ProfileElementSequence, opts):
+ print("Checking PE-Sequence structure...")
+ checker = CheckBasicStructure()
+ checker.check(pes)
+ print("All good!")
+
+def do_remove_pe(pes: ProfileElementSequence, opts):
+ new_pe_list = []
+ for pe in pes.pe_list:
+ identification = pe.identification
+ if identification:
+ if identification in opts.identification:
+ print("Removing PE %s (id=%u) from Sequence..." % (pe, identification))
+ continue
+ new_pe_list.append(pe)
+
+ pes.pe_list = new_pe_list
+ pes._process_pelist()
+ print("Writing %u PEs to file '%s'..." % (len(pes.pe_list), opts.output_file))
+ with open(opts.output_file, 'wb') as f:
+ f.write(pes.to_der())
+
+def do_remove_naa(pes: ProfileElementSequence, opts):
+ if not opts.naa_type in NAAs:
+ raise ValueError('unsupported NAA type %s' % opts.naa_type)
+ naa = NAAs[opts.naa_type]
+ print("Removing NAAs of type '%s' from Sequence..." % opts.naa_type)
+ pes.remove_naas_of_type(naa)
+ print("Writing %u PEs to file '%s'..." % (len(pes.pe_list), opts.output_file))
+ with open(opts.output_file, 'wb') as f:
+ f.write(pes.to_der())
+
+
+if __name__ == '__main__':
+ opts = parser.parse_args()
+
+ with open(opts.INPUT_UPP, 'rb') as f:
+ pes = ProfileElementSequence.from_der(f.read())
+
+ print("Read %u PEs from file '%s'" % (len(pes.pe_list), opts.INPUT_UPP))
+
+ if opts.command == 'split':
+ do_split(pes, opts)
+ elif opts.command == 'dump':
+ do_dump(pes, opts)
+ elif opts.command == 'check':
+ do_check(pes, opts)
+ elif opts.command == 'remove-pe':
+ do_remove_pe(pes, opts)
+ elif opts.command == 'remove-naa':
+ do_remove_naa(pes, opts)
+ else:
+ parser.print_help(sys.stderr)
+ sys.exit(2)
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/37011?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: I396bcd594e0628dfc26bd90233317a77e2f91b20
Gerrit-Change-Number: 37011
Gerrit-PatchSet: 1
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-MessageType: newchange