Skip to content

Loading builds...

Changes

#3046 (Apr 7, 2026, 5:13:36 PM)

filesystem: JsonEditor: offer interactive retry on error

When json.loads() fails (e.g. the user made a syntax mistake), prompt
the user with "Re-open file for editing? [y]es/[n]o:" and loop back to
the editor if they answer 'y' or 'yes'.  If the user declines, return
the original unmodified value so no write is attempted; the temp file
is still cleaned up by __exit__() in that case.

Change-Id: I9161b7becea0d8dfd3f5f740fbb253da2f061a1d
Related: OS#6899
Vadim Yanitskiy at

#3045 (Apr 7, 2026, 4:56:44 PM)

tests: fix TransRecEF _test_de_encode to operate at file level

Previously, _test_de_encode vectors for TransRecEF subclasses were tested
via decode_record_hex()/encode_record_hex(), i.e. one record at a time,
with the decoded value being a scalar.

Switch test_de_encode_record() in TransRecEF_Test to use decode_hex() /
encode_hex() instead, so that vectors represent whole-file content
(decoded value is a list of records) -- consistent with how LinFixedEF
handles _test_de_encode.  Update all existing vectors accordingly.

Change-Id: I4a9610f9ee39833cd0c90f64f89f5fbdd6f0846d
Vadim Yanitskiy at

#3044 (Apr 7, 2026, 4:39:56 PM)

pySim/ts_51_011.py: add multi-record test vector for EF_PL

Change-Id: I9f7a444b18056b1683cbd52a25af950125531746
Vadim Yanitskiy at

#3043 (Apr 7, 2026, 4:23:01 PM)

filesystem: JsonEditor: use NamedTemporaryFile

A plain NamedTemporaryFile is sufficient here: we only need a single
file, not a directory to hold it.  Using NamedTemporaryFile is simpler
(no subdirectory to manage) and gives us a .json suffix for free,
which editors use for syntax highlighting.

Change-Id: If3b0bd0fcc90732407dbd03b9cc883f7abeb948e
Vadim Yanitskiy at

#3042 (Apr 7, 2026, 3:48:49 PM)

filesystem: JsonEditor: use NamedTemporaryFile

A plain NamedTemporaryFile is sufficient here: we only need a single
file, not a directory to hold it.  Using NamedTemporaryFile is simpler
(no subdirectory to manage) and gives us a .json suffix for free,
which editors use for syntax highlighting.

Change-Id: If3b0bd0fcc90732407dbd03b9cc883f7abeb948e
Vadim Yanitskiy at

#3041 (Apr 7, 2026, 3:31:19 PM)

filesystem: JsonEditor: offer interactive retry on error

When json.loads() fails (e.g. the user made a syntax mistake), prompt
the user with "Re-open file for editing? [y]es/[n]o:" and loop back to
the editor if they answer 'y' or 'yes'.  If the user declines, return
the original unmodified value so no write is attempted; the temp file
is still cleaned up by __exit__() in that case.

Change-Id: I9161b7becea0d8dfd3f5f740fbb253da2f061a1d
Related: OS#6899
Vadim Yanitskiy at

#3040 (Apr 7, 2026, 3:13:37 PM)

filesystem: edit_{binary,record}_decoded: add encode/decode examples

When invoking `edit_binary_decoded` or `edit_record_decoded`, the
temp file opened in the editor now contains the EF's encode/decode
test vectors as //-comment lines below the JSON content, similar to
how 'git commit' appends comments to the commit message template.
The comment block is stripped before JSON parsing on save,
so it has no effect on the written data.

The feature is implemented via a new module-level JsonEditor context
manager class that encapsulates the full edit cycle:

* write JSON + examples to a TemporaryDirectory
* invoke the editor
* read back, strip //-comments, parse and return the result

Change-Id: I5a046a9c7ba7e08a98cf643d5a26bc669539b38f
Related: OS#6900
Vadim Yanitskiy at

#3039 (Apr 2, 2026, 10:55:48 AM)

pysim/pcsc: do not use getProtocol for protocol selection

The documentation of the getProtocol provided by pyscard says:

"Return bit mask for the protocol of connection, or None if no
protocol set. The return value is a bit mask of
CardConnection.T0_protocol, CardConnection.T1_protocol,
CardConnection.RAW_protocol, CardConnection.T15_protocol"

This suggests that the purpose of getProtocol is not to determine
which protocols are supported. Its purpose is to determine which
protocol is currently selected (either through auto selection or
through the explicit selection made by the API user). This means
we are using getProtocol wrong.

So far this was no problem, since the auto-selected protocol
should be a supported protocol anyway. However, the automatic
protocol selection may not always return a correct result (see
bug report from THD-siegfried [1]).

Let's not trust the automatic protocol selection. Instead let's
parse the ATR and make the decision based on the TD1/TD2 bytes).

[1] https://osmocom.org/issues/6952

Related: OS#6952
Change-Id: Ib119948aa68c430e42ac84daec8b9bd542db7963
pmaier@sysmocom.de at

#3038 (Apr 1, 2026, 1:53:30 PM)

filesystem: edit_{binary,record}_decoded: add encode/decode examples

When invoking `edit_binary_decoded` or `edit_record_decoded`, the
temp file opened in the editor now contains the EF's encode/decode
test vectors as //-comment lines below the JSON content, similar to
how 'git commit' appends comments to the commit message template.
The comment block is stripped before JSON parsing on save,
so it has no effect on the written data.

The feature is implemented via a new module-level JsonEditor context
manager class that encapsulates the full edit cycle:

* write JSON + examples to a TemporaryDirectory
* invoke the editor
* read back, strip //-comments, parse and return the result

Change-Id: I5a046a9c7ba7e08a98cf643d5a26bc669539b38f
Related: OS#6900
Vadim Yanitskiy at

#3037 (Apr 1, 2026, 1:35:58 PM)

filesystem: JsonEditor: offer interactive retry on error

When json.loads() fails (e.g. the user made a syntax mistake), prompt
the user with "Re-open file for editing? [y]es/[n]o:" and loop back to
the editor if they answer 'y' or 'yes'.  If the user declines, return
the original unmodified value so no write is attempted; the temp file
is still cleaned up by __exit__() in that case.

Change-Id: I9161b7becea0d8dfd3f5f740fbb253da2f061a1d
Related: OS#6899
Vadim Yanitskiy at

#3036 (Apr 1, 2026, 1:18:23 PM)

filesystem: JsonEditor: use NamedTemporaryFile

A plain NamedTemporaryFile is sufficient here: we only need a single
file, not a directory to hold it.  Using NamedTemporaryFile is simpler
(no subdirectory to manage) and gives us a .json suffix for free,
which editors use for syntax highlighting.

Change-Id: If3b0bd0fcc90732407dbd03b9cc883f7abeb948e
Vadim Yanitskiy at

#3035 (Apr 1, 2026, 1:00:49 PM)

docs: auto-generate Card Filesystem Reference

Add a Sphinx extension (docs/pysim_fs_sphinx.py) that hooks into the
builder-inited event and generates docs/filesystem.rst before Sphinx
reads any source files.

The generated page contains a hierarchical listing of all implemented
EFs and DFs, organised by application/specification (UICC/TS 102 221,
ADF.USIM/TS 31.102, ADF.ISIM/TS 31.103, SIM/TS 51.011).  For each file,
the class docstring and any _test_de_encode / _test_decode vectors
are included as an encoding/decoding example table.

docs/filesystem.rst is fully generated at build time and is therefore
added to .gitignore.

Add tests/unittests/test_fs_coverage.py that walks all pySim.* modules
and verifies that every CardProfile, CardApplication, and standalone
CardDF subclass with EF/DF children is either listed in the SECTIONS
(and will appear in the docs) or explicitly EXCLUDED.

Change-Id: I06ddeefc6c11e04d7c24e116f3f39c8a6635856f
Related: OS#6316
Vadim Yanitskiy at

#3034 (Mar 31, 2026, 10:45:43 PM)

filesystem: JsonEditor: use NamedTemporaryFile

A plain NamedTemporaryFile is sufficient here: we only need a single
file, not a directory to hold it.  Using NamedTemporaryFile is simpler
(no subdirectory to manage) and gives us a .json suffix for free,
which editors use for syntax highlighting.

Change-Id: If3b0bd0fcc90732407dbd03b9cc883f7abeb948e
Vadim Yanitskiy at

#3033 (Mar 31, 2026, 10:28:14 PM)

docs: auto-generate Card Filesystem Reference

Add a Sphinx extension (docs/pysim_fs_sphinx.py) that hooks into the
builder-inited event and generates docs/filesystem.rst before Sphinx
reads any source files.

The generated page contains a hierarchical listing of all implemented
EFs and DFs, organised by application/specification (UICC/TS 102 221,
ADF.USIM/TS 31.102, ADF.ISIM/TS 31.103, SIM/TS 51.011).  For each file,
the class docstring and any _test_de_encode / _test_decode vectors
are included as an encoding/decoding example table.

docs/filesystem.rst is fully generated at build time and is therefore
added to .gitignore.

Add tests/unittests/test_fs_coverage.py that walks all pySim.* modules
and verifies that every CardProfile, CardApplication, and standalone
CardDF subclass with EF/DF children is either listed in the SECTIONS
(and will appear in the docs) or explicitly EXCLUDED.

Change-Id: I06ddeefc6c11e04d7c24e116f3f39c8a6635856f
Related: OS#6316
Vadim Yanitskiy at

#3032 (Mar 31, 2026, 10:10:42 PM)

filesystem: JsonEditor: offer interactive retry on error

When json.loads() fails (e.g. the user made a syntax mistake), prompt
the user with "Re-open file for editing? [y]es/[n]o:" and loop back to
the editor if they answer 'y' or 'yes'.  If the user declines, return
the original unmodified value so no write is attempted; the temp file
is still cleaned up by __exit__() in that case.

Change-Id: I9161b7becea0d8dfd3f5f740fbb253da2f061a1d
Related: OS#6899
Vadim Yanitskiy at

#3031 (Mar 31, 2026, 9:53:05 PM)

filesystem: edit_{binary,record}_decoded: add encode/decode examples

When invoking `edit_binary_decoded` or `edit_record_decoded`, the
temp file opened in the editor now contains the EF's encode/decode
test vectors as //-comment lines below the JSON content, similar to
how 'git commit' appends comments to the commit message template.
The comment block is stripped before JSON parsing on save,
so it has no effect on the written data.

The feature is implemented via a new module-level JsonEditor context
manager class that encapsulates the full edit cycle:

* write JSON + examples to a TemporaryDirectory
* invoke the editor
* read back, strip //-comments, parse and return the result

Change-Id: I5a046a9c7ba7e08a98cf643d5a26bc669539b38f
Related: OS#6900
Vadim Yanitskiy at

#3030 (Mar 31, 2026, 1:45:59 PM)

docs/conf.py: silence autosectionlabel duplicate-label warnings

sphinxarg.ext generates generic sub-headings ("Named arguments",
"Positional arguments", "Sub-commands", "General options", ...) for
every argparse command and tool.  These repeat across many files and
trigger large numbers of autosectionlabel duplicate-label warnings.

Two-pronged fix:

* `autosectionlabel_maxdepth = 3` eliminates the depth-4+ warnings
  (sub-headings inside each individual command block).
* `suppress_warnings` per file silences the residual depth-3 collisions
  ("serial reader", "decode_hex", "sub-commands", ...) that still
  appear across tool documentation files.

Cross-references into these generic argparse-generated sections are not
a supported use-case, so suppressing the warnings is appropriate.

Change-Id: I9cdf2a4f6cbd435b16b90ab668205600ffd7c3b0
Vadim Yanitskiy at

#3029 (Mar 31, 2026, 1:28:31 PM)

docs: auto-generate Card Filesystem Reference

Add a Sphinx extension (docs/pysim_fs_sphinx.py) that hooks into the
builder-inited event and generates docs/filesystem.rst before Sphinx
reads any source files.

The generated page contains a hierarchical listing of all implemented
EFs and DFs, organised by application/specification (UICC/TS 102 221,
ADF.USIM/TS 31.102, ADF.ISIM/TS 31.103, SIM/TS 51.011).  For each file,
the class docstring and any _test_de_encode / _test_decode vectors
are included as an encoding/decoding example table.

docs/filesystem.rst is fully generated at build time and is therefore
added to .gitignore.

Change-Id: I06ddeefc6c11e04d7c24e116f3f39c8a6635856f
Related: OS#6316
Vadim Yanitskiy at

#3028 (Mar 31, 2026, 1:11:03 PM)

filesystem: edit_{binary,record}_decoded: add encode/decode examples

When invoking `edit_binary_decoded` or `edit_record_decoded`, the
temp file opened in the editor now contains the EF's encode/decode
test vectors as //-comment lines below the JSON content, similar to
how 'git commit' appends comments to the commit message template.
The comment block is stripped before JSON parsing on save,
so it has no effect on the written data.

The feature is implemented via a new module-level JsonEditor context
manager class that encapsulates the full edit cycle:

* write JSON + examples to a TemporaryDirectory
* invoke the editor
* read back, strip //-comments, parse and return the result

Change-Id: I5a046a9c7ba7e08a98cf643d5a26bc669539b38f
Related: OS#6900
Vadim Yanitskiy at

#3027 (Mar 31, 2026, 12:53:34 PM)

filesystem: JsonEditor: offer interactive retry on error

When json.loads() fails (e.g. the user made a syntax mistake), prompt
the user with "Re-open file for editing? [y]es/[n]o:" and loop back to
the editor if they answer 'y' or 'yes'.  If the user declines, return
the original unmodified value so no write is attempted; the temp file
is still cleaned up by __exit__() in that case.

Change-Id: I9161b7becea0d8dfd3f5f740fbb253da2f061a1d
Related: OS#6899
Vadim Yanitskiy at

#3026 (Mar 31, 2026, 12:35:57 PM)

filesystem: JsonEditor: use NamedTemporaryFile

A plain NamedTemporaryFile is sufficient here: we only need a single
file, not a directory to hold it.  Using NamedTemporaryFile is simpler
(no subdirectory to manage) and gives us a .json suffix for free,
which editors use for syntax highlighting.

Change-Id: If3b0bd0fcc90732407dbd03b9cc883f7abeb948e
Vadim Yanitskiy at

#3025 (Mar 31, 2026, 12:18:26 PM)

docs/conf.py: add autodoc_mock_imports for klein and twisted

The eSIM SM-DP+ server modules (`pySim.esim.es2p`, `pySim.esim.es9p`,
`pySim.esim.http_json_api`) unconditionally import optional server-side
dependencies at module level:

  pySim.esim.es2p          -- from klein import Klein
  pySim.esim.http_json_api -- from twisted.web.server import Request

Both imports fail during a docs build if the packages are absent or
broken, causing three "autodoc: failed to import" warnings and three
missing chapters in the generated manual.

Even when klein and twisted are installed, twisted 23.10.0 (the
version pulled in transitively by smpp.twisted3's `Twisted~=23.10.0`
constraint) is incompatible with Python 3.13+ because twisted.web.http
unconditionally executes `import cgi`, a module that was removed from
the standard library in Python 3.13.

Fix: add `autodoc_mock_imports = ['klein', 'twisted']` to conf.py.
Sphinx inserts mock entries into sys.modules before each autodoc import
attempt, so the modules can be imported and documented without requiring
the real packages to be importable at build time.

Change-Id: I71650466f02a6a6d150650deed167c05d2cb6e64
Vadim Yanitskiy at

#3024 (Mar 31, 2026, 11:40:14 AM)

pysim/pcsc: do not use getProtocol for protocol selection

The documentation of the getProtocol provided by pyscard says:

"Return bit mask for the protocol of connection, or None if no
protocol set. The return value is a bit mask of
CardConnection.T0_protocol, CardConnection.T1_protocol,
CardConnection.RAW_protocol, CardConnection.T15_protocol"

This suggests that the purpose of getProtocol is not to determine
which protocols are supported. Its purpose is to determine which
protocol is currently selected (either through auto selection or
through the explicit selection made by the API user). This means
we are using getProtocol wrong.

So far this was no problem, since the auto-selected protocol
should be a supported protocol anyway. However, the automatic
protocol selection may not always return a correct result (see
bug report from THD-siegfried [1]).

Let's not trust the automatic protocol selection. Instead let's
parse the ATR and make the decision based on the TD1/TD2 bytes).

[1] https://osmocom.org/issues/6952

Related: OS#6952
Change-Id: Ib119948aa68c430e42ac84daec8b9bd542db7963
pmaier@sysmocom.de at

#3023 (Mar 31, 2026, 9:46:56 AM)

pySim-read: remove import random

In pySim-read we do not have to compute any random numbers, so
we may remove random from the imports

Change-Id: Iae4ee6aafb339cc682345299b92b4ecd0bbca14e
pmaier@sysmocom.de at

#3022 (Mar 30, 2026, 11:57:21 PM)

filesystem: JsonEditor: offer interactive retry on error

When json.loads() fails (e.g. the user made a syntax mistake), prompt
the user with "Re-open file for editing? [y]es/[n]o:" and loop back to
the editor if they answer 'y' or 'yes'.  If the user declines, return
the original unmodified value so no write is attempted; the temp file
is still cleaned up by __exit__() in that case.

Change-Id: I9161b7becea0d8dfd3f5f740fbb253da2f061a1d
Related: OS#6899
Vadim Yanitskiy at

#3021 (Mar 30, 2026, 11:26:49 PM)

filesystem: JsonEditor: use NamedTemporaryFile

A plain NamedTemporaryFile is sufficient here: we only need a single
file, not a directory to hold it.  Using NamedTemporaryFile is simpler
(no subdirectory to manage) and gives us a .json suffix for free,
which editors use for syntax highlighting.

Change-Id: If3b0bd0fcc90732407dbd03b9cc883f7abeb948e
Vadim Yanitskiy at

#3020 (Mar 30, 2026, 11:09:08 PM)

filesystem: edit_{binary,record}_decoded: add encode/decode examples

When invoking `edit_binary_decoded` or `edit_record_decoded`, the
temp file opened in the editor now contains the EF's encode/decode
test vectors as //-comment lines below the JSON content, similar to
how 'git commit' appends comments to the commit message template.
The comment block is stripped before JSON parsing on save,
so it has no effect on the written data.

The feature is implemented via a new module-level JsonEditor context
manager class that encapsulates the full edit cycle:

* write JSON + examples to a TemporaryDirectory
* invoke the editor
* read back, strip //-comments, parse and return the result

Change-Id: I5a046a9c7ba7e08a98cf643d5a26bc669539b38f
Related: OS#6900
Vadim Yanitskiy at

#3019 (Mar 30, 2026, 10:51:23 PM)

docs: auto-generate Card Filesystem Reference

Add a Sphinx extension (docs/pysim_fs_sphinx.py) that hooks into the
builder-inited event and generates docs/filesystem.rst before Sphinx
reads any source files.

The generated page contains a hierarchical listing of all implemented
EFs and DFs, organised by application/specification (UICC/TS 102 221,
ADF.USIM/TS 31.102, ADF.ISIM/TS 31.103, SIM/TS 51.011).  For each file,
the class docstring and any _test_de_encode / _test_decode vectors
are included as an encoding/decoding example table.

docs/filesystem.rst is fully generated at build time and is therefore
added to .gitignore.

Change-Id: I06ddeefc6c11e04d7c24e116f3f39c8a6635856f
Related: OS#6316
Vadim Yanitskiy at

#3018 (Mar 30, 2026, 3:37:14 PM)

docs/conf.py: add autodoc_mock_imports for klein and twisted

The eSIM SM-DP+ server modules (`pySim.esim.es2p`, `pySim.esim.es9p`,
`pySim.esim.http_json_api`) unconditionally import optional server-side
dependencies at module level:

  pySim.esim.es2p          -- from klein import Klein
  pySim.esim.http_json_api -- from twisted.web.server import Request

Both imports fail during a docs build if the packages are absent or
broken, causing three "autodoc: failed to import" warnings and three
missing chapters in the generated manual.

Even when klein and twisted are installed, twisted 23.10.0 (the
version pulled in transitively by smpp.twisted3's `Twisted~=23.10.0`
constraint) is incompatible with Python 3.13+ because twisted.web.http
unconditionally executes `import cgi`, a module that was removed from
the standard library in Python 3.13.

Fix: add `autodoc_mock_imports = ['klein', 'twisted']` to conf.py.
Sphinx inserts mock entries into sys.modules before each autodoc import
attempt, so the modules can be imported and documented without requiring
the real packages to be importable at build time.

Change-Id: I71650466f02a6a6d150650deed167c05d2cb6e64
Vadim Yanitskiy at

#3017 (Mar 30, 2026, 3:19:43 PM)

docs/conf.py: silence autosectionlabel duplicate-label warnings

sphinxarg.ext generates generic sub-headings ("Named arguments",
"Positional arguments", "Sub-commands", "General options", ...) for
every argparse command and tool.  These repeat across many files and
trigger large numbers of autosectionlabel duplicate-label warnings.

Two-pronged fix:

* `autosectionlabel_maxdepth = 3` eliminates the depth-4+ warnings
  (sub-headings inside each individual command block).
* `suppress_warnings` per file silences the residual depth-3 collisions
  ("serial reader", "decode_hex", "sub-commands", ...) that still
  appear across tool documentation files.

Cross-references into these generic argparse-generated sections are not
a supported use-case, so suppressing the warnings is appropriate.

Change-Id: I9cdf2a4f6cbd435b16b90ab668205600ffd7c3b0
Vadim Yanitskiy at

#3016 (Mar 30, 2026, 3:02:10 PM)

docs/legacy: fix typo "EF,IMSI" -> "EF.IMSI"

Change-Id: I1f246ec008a57b2373ed3f5531ab4166101f4dd0
Vadim Yanitskiy at

#3015 (Mar 30, 2026, 2:44:44 PM)

docs/conf.py: silence autosectionlabel duplicate-label warnings

sphinxarg.ext generates generic sub-headings ("Named arguments",
"Positional arguments", "Sub-commands", "General options", ...) for
every argparse command and tool.  These repeat across many files and
trigger large numbers of autosectionlabel duplicate-label warnings.

Two-pronged fix:

* `autosectionlabel_maxdepth = 3` eliminates the depth-4+ warnings
  (sub-headings inside each individual command block).
* `suppress_warnings` per file silences the residual depth-3 collisions
  ("serial reader", "decode_hex", "sub-commands", ...) that still
  appear across tool documentation files.

Cross-references into these generic argparse-generated sections are not
a supported use-case, so suppressing the warnings is appropriate.

Change-Id: I9cdf2a4f6cbd435b16b90ab668205600ffd7c3b0
Vadim Yanitskiy at

#3014 (Mar 30, 2026, 2:27:12 PM)

docs/put_key-tutorial: fix three typos

  "verifiation"        -> "verification"
  "this is identifies" -> "this identifies" (extra word)
  "and and"            -> "and" (doubled word)

Change-Id: I1ae6b01638cc2c3dd8355ba801f85cc179ca8bd3
Vadim Yanitskiy at

#3013 (Mar 30, 2026, 2:09:45 PM)

docs/card-key-provider: fix heading levels and typo

The "ADM PIN" and "SCP02 / SCP03" sub-sections of "Field naming" used
the '~' heading character, which Sphinx resolved to level 4 - skipping
level 3 and throwing build ERRORs.  As a result, both sub-sections
had no heading at all.  Change both to '^' (level 3) to match the
other sub-sections in this file.

While at it, fix a typo: "consisting if" -> "consisting of".

Change-Id: Ia56efc7fadcc0fd62e87e63850b929d2f80851ba
Vadim Yanitskiy at

#3012 (Mar 30, 2026, 1:50:02 PM)

docs/shell: fix copy-paste typos in editor command descriptions

Two adjacent commands (`edit_record_decoded`, `edit_binary_decoded`)
had identical copy-pasted error messages with three typos each:

  "modificatiosn" -> "modifications"
  "us the"        -> "use the"
  "comamdn"       -> "command"

Change-Id: Ie23baba4634e2cc40f81439fb11b102778aed1f6
Vadim Yanitskiy at

#3011 (Mar 30, 2026, 1:32:28 PM)

docs/saip-tool: fix typo "insertaion" -> "insertion"

Change-Id: Ie9c9235ec964a15fab19d6ca5a83b2b1ddf07e7b
Vadim Yanitskiy at

#3010 (Mar 25, 2026, 2:36:17 PM)

pySim/EF.SMSP: fix encoding of TP-Destination Address

The TP-Destination Address in EF.SMSP uses the same encoding as the
TS-Service Centre Address field. However, even though the encoding
of both fields looks almost identical, it actually isn't.

The TS-Service Centre Address field encodes the length field as
octets required for the call_number + one octet for ton_npi.
(see also: 3GPP TS 24.011, section 8.2.5.2)

The TP-Destination Address uses the number of digits of the
call_number directly in the length field.
(see also: 3GPP TS 23.040, section 9.1.2.5)

Related: SYS#7765
Change-Id: I55c123c9e244e5a6e71a0348f5d476ef03e618e8
pmaier@sysmocom.de at

#3009 (Mar 25, 2026, 1:18:52 PM)

pysim/pcsc: do not use getProtocol for protocol selection

The documentation of the getProtocol provided by pyscard says:

"Return bit mask for the protocol of connection, or None if no
protocol set. The return value is a bit mask of
CardConnection.T0_protocol, CardConnection.T1_protocol,
CardConnection.RAW_protocol, CardConnection.T15_protocol"

This suggests that the purpose of getProtocol is not to determine
which protocols are supported. Its purpose is to determine which
protocol is currently selected (either through auto selection or
through the explicit selection made by the API user). This means
we are using getProtocol wrong.

So far this was no problem, since the auto-selected protocol
should be a supported protocol anyway. However, the automatic
protocol selection may not always return a correct result (see
bug report from THD-siegfried [1]).

Let's not trust the automatic protocol selection. Instead let's
parse the ATR and make the decision based on the TD1/TD2 bytes).

[1] https://osmocom.org/issues/6952

Related: OS#6952
Change-Id: Ib119948aa68c430e42ac84daec8b9bd542db7963
pmaier@sysmocom.de at

#3008 (Mar 25, 2026, 1:01:21 PM)

global_platform: install_cap_parser: argument groups cannot be nested

pySim-shell currently does not work on systems with Python 3.14+:

  File ".../pysim/pySim/global_platform/__init__.py", line 868, in AddlShellCommands
    install_cap_parser_inst_prm_g_grp = install_cap_parser_inst_prm_g.add_argument_group()
  File "/usr/lib/python3.14/argparse.py", line 1794, in add_argument_group
    raise ValueError('argument groups cannot be nested')
  ValueError('argument groups cannot be nested')

The problem is that install_cap_parser creates a nested group inside
of mutually exclusive group.  argparse never supported group nesting
properly, so it has been deprecated since Python 3.11, and eventually
got removed in Python 3.14.

Remove group nesting, adjust the usage string, and implement the
mutual exclusiveness enforcement manually in do_install_cap().

Change-Id: Idddf72d5a745345e134b23f2f01e0257d0667579
Vadim Yanitskiy at

#3007 (Mar 25, 2026, 12:43:43 PM)

global_platform: refactor gen_install_parameters()

gen_install_parameters() had contradictory logic: the outer guard
required all three arguments to be non-None/non-empty (making them
mutually inclusive), while the inner checks then treated each one
as optional.

Make each parameter independently optional (defaulting to None) and
remove the all-or-nothing check.  Simplify the function body to a
straightforward single-pass construction of system_specific_params.

Change-Id: I8756fb38016cdf0527fe2e21edb44381d1dc557f
Vadim Yanitskiy at

#3006 (Mar 25, 2026, 12:02:53 PM)

docs/put_key: add tutorial that explains how to manage global platform keys

With the increased interest in using GlobalPlatform features of
UICC and eUICCs (OTA-SMS, applets, etc.), also comes an increased
interest in how the related GlobalPlatform keys can be managed
(key rotation, adding/removing keysets from/to a Security Domain).

Unfortunately, many aspects of this topic are not immediately
obvious for the average user. Let's add a tutorial that contains
some practical examples to shine some light on the topic.

Related: SYS#7881
Change-Id: I163dfedca3df572cb8442e9a4a280e6c5b00327e
pmaier@sysmocom.de at

#3005 (Mar 24, 2026, 12:23:29 PM)

docs/put_key: add tutorial that explains how to manage global platform keys

With the increased interest in using GlobalPlatform features of
UICC and eUICCs (OTA-SMS, applets, etc.), also comes an increased
interest in how the related GlobalPlatform keys can be managed
(key rotation, adding/removing keysets from/to a Security Domain).

Unfortunately, many aspects of this topic are not immediately
obvious for the average user. Let's add a tutorial that contains
some practical examples to shine some light on the topic.

Related: SYS#7881
Change-Id: I163dfedca3df572cb8442e9a4a280e6c5b00327e
pmaier@sysmocom.de at

#3004 (Mar 23, 2026, 5:16:40 PM)

pysim/pcsc: do not use getProtocol for protocol selection

The documentation of the getProtocol provided by pyscard says:

"Return bit mask for the protocol of connection, or None if no
protocol set. The return value is a bit mask of
CardConnection.T0_protocol, CardConnection.T1_protocol,
CardConnection.RAW_protocol, CardConnection.T15_protocol"

This suggests that the purpose of getProtocol is not to determine
which protocols are supported. Its purpose is to determine which
protocol is currently selected (either through auto selection or
through the explicit selection made by the API user). This means
we are using getProtocol wrong.

So far this was no problem, since the auto-selected protocol
should be a supported protocol anyway. However, the automatic
protocol selection may not always return a correct result (see
bug report from THD-siegfried [1]).

Let's not trust the automatic protocol selection. Instead let's
parse the ATR and make the decision based on the TD1/TD2 bytes).

[1] https://osmocom.org/issues/6952

Related: OS#6952
Change-Id: Ib119948aa68c430e42ac84daec8b9bd542db7963
pmaier@sysmocom.de at

#3003 (Mar 23, 2026, 4:59:08 PM)

pySim/pcsc/cosmetic: reformat comment

Change-Id: Ic04bdfbc6727cc670679c377c1afd1de53504b8f
pmaier@sysmocom.de at

#3002 (Mar 23, 2026, 4:25:29 PM)

pySim/EF.SMSP: fix encoding of TP-Destination Address

The TP-Destination Address in EF.SMSP uses the same encoding as the
TS-Service Centre Address field. However, even though the encoding
of both fields looks almost identical, it actually isn't.

The TS-Service Centre Address field encodes the length field as
octets required for the call_number + one octet for ton_npi.
(see also: 3GPP TS 24.011, section 8.2.5.2)

The TP-Destination Address uses the number of digits of the
call_number directly in the length field.
(see also: 3GPP TS 23.040, section 9.1.2.5)

Related: SYS#7765
Change-Id: I55c123c9e244e5a6e71a0348f5d476ef03e618e8
pmaier@sysmocom.de at

#3001 (Mar 23, 2026, 4:08:04 PM)

pySim/EF.SMSP: remove superflous line break

Change-Id: Ie02e02546e708e2c339810812188bd8e8af2a720
pmaier@sysmocom.de at

#3000 (Mar 23, 2026, 3:50:17 PM)

pySim/EF.SMSP: add an additional de_encode test for EF_SMSP

Let's add another testvector where we test what happens when we populate
none of the fields except for the tp_sc_addr.

Related: SYS#7765
Change-Id: I12b600ab17d1acfdddaffe6006095acf1a4228c9
pmaier@sysmocom.de at

#2999 (Mar 23, 2026, 12:54:04 PM)

transport: change APDU format paradigm

Unfortunately we have mixed up the concept of TPDUs and APDUs in
earlier versions of pySim-shell. This lead to problems with
detecteding the APDU case properly (see also ISO/IEC 7816-3) and
also prevented us from adding support for T=1.

This problem has been fixed long time ago and all APDUs sent from
the pySim-shell code should be well formed and valid according to
ISO/IEC 7816-3.

To ensure that we continue to format APDUs correctly as APDUs (and
not TPDUs) we have added a mechanism to the LinkBase class that
would either raise an exception or print a warning if someone
mistakenly tries to send an APDU that is really a TPDU. Whether a
warning is printed or an exception is raised is controlled via the
apdu_strict member in the LinkBase class, which is false (print
warning only) by default.

The reason why we have implemneted the mechanism this way was
because we wanted to ensure that existing APDU scripts (pySim-shell
apdu command) keep working, even though when those scripts uses
APDUs which are formally invalid.

Sending a TPDU instead of an APDU via a T=0 link will still work
in almost all cases. This is also the reason why this problem
slipped through unnoticed for long time. However, there may still
be subtile problems araising from this practice. The root of the
problem is that it is impossible to distinguish between APDU case
3 and 4 when a TPDU instead of an APDU is sent. However in order
to handle a case 4 APDU correctly we must be able to distinguish
the APDU case correctly to handle the case correctly.
ETSI TS 102 221, section 7.3.1.1.4, clause 4 is very clear about
the fact that not (only) the status word (e.g. 61xx) but the
APDU case is what matters.

To complete the logic in LinkBaseTpdu and to maintain compatibility
(older APDU scripts), we must still be able to switch between the
'apdu_strict' mode and the non-strict mode. However, since
pySim-shell, pySim-prog and pySim-read internally use proper APDUs,
we may enable the 'apdu_strict' mode by default.

At the same time we will limit the effect of pySim-shell's
apdu_strict setable to the apdu command only. By doing so, the
bahviour of the apdu command is not altered. Users will still
have to enable the 'strict' mode explicitly. At the same time
all the internal functionality of pySim-shell will always use
the 'strict' mode.

Related: OS#6970
Change-Id: I9a531a825def318b28bf58291d811cf119003fab
pmaier@sysmocom.de at

#2998 (Mar 21, 2026, 2:04:13 AM)

esim/saip: raise an exception properly

Change-Id: Ia3749c02120fdc16e556214d0461cbeca032447b
laforge at

#2997 (Mar 21, 2026, 1:46:43 AM)

ara_m: fix undefined variable used in a format-string

Change-Id: I310a5d461bae2b5e4d8e07097000b079c23aa0f6
laforge at

#2996 (Mar 21, 2026, 1:29:16 AM)

ts_31_102: fix description for EF_5GS3GPPLOCI

Change-Id: I9cf3adfce65090fedb3f0fd33c9b3d15a2c5fb8c
laforge at

#2995 (Mar 21, 2026, 1:11:47 AM)

cdma_ruim: fix inaccurate comment for EF_AD

Change-Id: I71ea27fd30e44685ff35f49843072ca392995973
laforge at

#2994 (Mar 21, 2026, 12:46:21 AM)

ota: OtaAlgo{Crypt,Auth}: fix algo_auth vs algo_crypt

* OtaAlgoCrypt.from_keyset() searches by `otak.algo_crypt`
  but the error message prints `otak.algo_auth`.  Should be
  `otak.algo_crypt` instead.

* OtaAlgoAuth.__init__() checks `algo_auth` but the error message
  prints `algo_crypt`.  Should be `otak.algo_auth` instead.

Change-Id: Ia636fffaeadc68e3f6d5b65d477e753834c95895
laforge at

#2993 (Mar 21, 2026, 12:28:53 AM)

sms: fix flags_construct in SMS_DELIVER

* field `tp_rp` appears at bit positions 7 and 5
** bit 7 should be `tp_rp` (Reply Path)
** bit 5 should be `tp_sri` (Status Report Indication)
* field `tp_lp` is completely missing
** should be at bit position 3

Change-Id: I0274849f0fa07281b5e050af429ffda7d249f9e8
laforge at

#2992 (Mar 21, 2026, 12:11:23 AM)

global_platform: fix typo in SupportedTlsCipherSuitesForScp81

The attribute name is misspelled.  The BER-TLV infrastructure looks
for `_construct`; this typo means `SupportedTlsCipherSuitesForScp81`
will never decode its content.

Change-Id: I0f637951b0eeb7eca2a8b543baa737f216a935ed
laforge at

#2991 (Mar 20, 2026, 11:53:57 PM)

global_platform: fix docstring for Scp03SessionKeys._get_icv()

Change-Id: I8983bc27f581295544360ba8b4ae1d28b3ea850f
laforge at

#2990 (Mar 20, 2026, 11:36:27 PM)

utils: dec_plmn(): remove redundant call

Change-Id: Ic95c3992ed57eb8fee952ec2dc7f092dd7689579
laforge at

#2989 (Mar 20, 2026, 11:18:58 PM)

ara_m: fix exceptions not being raised properly

Exceptions are meant to be thrown/raised, not returned.

Change-Id: Id799c264447e22887edcd2dc7eb991cf0af1bbfc
laforge at

#2988 (Mar 20, 2026, 11:01:28 PM)

utils: DataObjectCollection.encode(): fix TypeError

`members_by_name` is a plain dictionary.  Calling it with `()` raises:

  TypeError: 'dict' object is not callable

Change-Id: I7e0c09aa7303f1506fe3a025fdc3779919dd0e6c
laforge at

#2987 (Mar 20, 2026, 10:44:01 PM)

global_platform: fix s/GET/STORE/ DATA in docs

Both `do_store_data` and `store_data` have identical docstrings that
incorrectly describe the command as GET DATA.  Should be "STORE DATA".
Take a chance to fix missing space between `v2.3` and `Section`.

Change-Id: I33fc80ab8ca50fadc38217b0005eec6169c8e34e
laforge at

#2986 (Mar 20, 2026, 10:26:29 PM)

global_platform: fix store_data() returning last chunk only

The loop builds up `response` across multiple STORE DATA blocks,
but the function returns only `data` - the response from the
*last* block.  It should return the accumulated response instead.

Change-Id: I3e15c8004d1e366e8c3896e559656622f48bb1a2
laforge at

#2985 (Mar 20, 2026, 10:09:02 PM)

global_platform: fix typo in ApplicationTemplate

The keyword argument should be `nested=`.  As written `ApplicationAID`
is silently ignored - `ApplicationTemplate` will not descend into its
nested TLVs.

Change-Id: If45dbb0c9b09fe53560d109957ce339267a9f2b0
laforge at

#2984 (Mar 20, 2026, 9:51:34 PM)

ts_31_102: EF_5G_PROSE_UIR: fix copy-pasted inner class name

Change-Id: I460e5ad70f35026d0d794271a4aef17323c14dfb
laforge at

#2983 (Mar 20, 2026, 9:33:56 PM)

ts_51_011: EF.EXT[6-7]: fix typo in desc

Change-Id: I93df1c9fd8a4d588ed7ed19ec2dc1d304412fc3d
laforge at

#2982 (Mar 20, 2026, 9:44:11 AM)

docs/put_key: add tutorial that explains how to manage global platform keys

With the increased interest in using GlobalPlatform features of
UICC and eUICCs (OTA-SMS, applets, etc.), also comes an increased
interest in how the related GlobalPlatform keys can be managed
(key rotation, adding/removing keysets from/to a Security Domain).

Unfortunately, many aspects of this topic are not immediately
obvious for the average user. Let's add a tutorial that contains
some practical examples to shine some light on the topic.

Related: SYS#7881
Change-Id: I163dfedca3df572cb8442e9a4a280e6c5b00327e
pmaier@sysmocom.de at

#2981 (Mar 19, 2026, 4:51:14 PM)

docs/put_key: add tutorial that explains how to manage global platform keys

With the increased interest in using GlobalPlatform features of
UICC and eUICCs (OTA-SMS, applets, etc.), also comes an increased
interest in how the related GlobalPlatform keys can be managed
(key rotation, adding/removing keysets from/to a Security Domain).

Unfortunately, many aspects of this topic are not immediately
obvious for the average user. Let's add a tutorial that contains
some practical examples to shine some light on the topic.

Related: SYS#7881
Change-Id: I163dfedca3df572cb8442e9a4a280e6c5b00327e
pmaier@sysmocom.de at

#2980 (Mar 19, 2026, 4:33:39 PM)

docs/put_key: add tutorial that explains how to manage global platform keys

With the increased interest in using GlobalPlatform features of
UICC and eUICCs (OTA-SMS, applets, etc.), also comes an increased
interest in how the related GlobalPlatform keys can be managed
(key rotation, adding/removing keysets from/to a Security Domain).

Unfortunately, many aspects of this topic are not immediately
obvious for the average user. Let's add a tutorial that contains
some practical examples to shine some light on the topic.

Related: SYS#7881
Change-Id: I163dfedca3df572cb8442e9a4a280e6c5b00327e
pmaier@sysmocom.de at

#2979 (Mar 19, 2026, 12:10:53 PM)

transport: change APDU format paradigm

Unfortunately we have mixed up the concept of TPDUs and APDUs in
earlier versions of pySim-shell. This lead to problems with
detecteding the APDU case properly (see also ISO/IEC 7816-3) and
also prevented us from adding support for T=1.

This problem has been fixed long time ago and all APDUs sent from
the pySim-shell code should be well formed and valid according to
ISO/IEC 7816-3.

To ensure that we continue to format APDUs correctly as APDUs (and
not TPDUs) we have added a mechanism to the LinkBase class that
would either raise an exception or print a warning if someone
mistakenly tries to send an APDU that is really a TPDU. Whether a
warning is printed or an exception is raised is controlled via the
apdu_strict member in the LinkBase class, which is false (print
warning only) by default.

The reason why we have implemneted the mechanism this way was
because we wanted to ensure that existing APDU scripts (pySim-shell
apdu command) keep working, even though when those scripts uses
APDUs which are formally invalid.

Sending a TPDU instead of an APDU via a T=0 link will still work
in almost all cases. This is also the reason why this problem
slipped through unnoticed for long time. However, there may still
be subtile problems araising from this practice. The root of the
problem is that it is impossible to distinguish between APDU case
3 and 4 when a TPDU instead of an APDU is sent. However in order
to handle a case 4 APDU correctly we must be able to distinguish
the APDU case correctly to handle the case correctly.
ETSI TS 102 221, section 7.3.1.1.4, clause 4 is very clear about
the fact that not (only) the status word (e.g. 61xx) but the
APDU case is what matters.

To complete the logic in LinkBaseTpdu and to maintain compatibility
(older APDU scripts), we must still be able to switch between the
'apdu_strict' mode and the non-strict mode. However, it makes sense
to do this on a per-api-call basis instead globally via a class
property.

At the same time we will limit the effect of pySim-shell's
apdu_strict setable to the apdu command only. By doing so, the
bahviour of the apdu command is not altered. Users will still
have to enable the 'strict' mode explicitly. At the same time
all the internal functionality of pySim-shell will always use
the 'strict' mode.

Related: OS#6970
Change-Id: I9a531a825def318b28bf58291d811cf119003fab
pmaier@sysmocom.de at

#2978 (Mar 17, 2026, 11:28:15 PM)

utils: DataObjectCollection.encode(): fix TypeError

`members_by_name` is a plain dictionary.  Calling it with `()` raises:

  TypeError: 'dict' object is not callable

Change-Id: I7e0c09aa7303f1506fe3a025fdc3779919dd0e6c
Vadim Yanitskiy at

#2977 (Mar 17, 2026, 11:10:45 PM)

ara_m: fix undefined variable used in a format-string

Change-Id: I310a5d461bae2b5e4d8e07097000b079c23aa0f6
Vadim Yanitskiy at

#2976 (Mar 17, 2026, 10:53:18 PM)

global_platform: fix typo in ApplicationTemplate

The keyword argument should be `nested=`.  As written `ApplicationAID`
is silently ignored - `ApplicationTemplate` will not descend into its
nested TLVs.

Change-Id: If45dbb0c9b09fe53560d109957ce339267a9f2b0
Vadim Yanitskiy at

#2975 (Mar 17, 2026, 10:35:36 PM)

esim/saip: raise an exception properly

Change-Id: Ia3749c02120fdc16e556214d0461cbeca032447b
Vadim Yanitskiy at

#2974 (Mar 17, 2026, 10:18:12 PM)

ts_31_102: fix description for EF_5GS3GPPLOCI

Change-Id: I9cf3adfce65090fedb3f0fd33c9b3d15a2c5fb8c
Vadim Yanitskiy at

#2973 (Mar 17, 2026, 10:00:42 PM)

global_platform: fix typo in SupportedTlsCipherSuitesForScp81

The attribute name is misspelled.  The BER-TLV infrastructure looks
for `_construct`; this typo means `SupportedTlsCipherSuitesForScp81`
will never decode its content.

Change-Id: I0f637951b0eeb7eca2a8b543baa737f216a935ed
Vadim Yanitskiy at

#2972 (Mar 17, 2026, 9:43:13 PM)

global_platform: fix store_data() returning last chunk only

The loop builds up `response` across multiple STORE DATA blocks,
but the function returns only `data` - the response from the
*last* block.  It should return the accumulated response instead.

Change-Id: I3e15c8004d1e366e8c3896e559656622f48bb1a2
Vadim Yanitskiy at

#2971 (Mar 17, 2026, 9:25:42 PM)

cdma_ruim: fix inaccurate comment for EF_AD

Change-Id: I71ea27fd30e44685ff35f49843072ca392995973
Vadim Yanitskiy at

#2970 (Mar 17, 2026, 9:08:17 PM)

ts_51_011: EF.EXT[6-7]: fix typo in desc

Change-Id: I93df1c9fd8a4d588ed7ed19ec2dc1d304412fc3d
Vadim Yanitskiy at

#2969 (Mar 17, 2026, 8:50:48 PM)

global_platform: fix s/GET/STORE/ DATA in docs

Both `do_store_data` and `store_data` have identical docstrings that
incorrectly describe the command as GET DATA.  Should be "STORE DATA".
Take a chance to fix missing space between `v2.3` and `Section`.

Change-Id: I33fc80ab8ca50fadc38217b0005eec6169c8e34e
Vadim Yanitskiy at

#2968 (Mar 17, 2026, 8:33:21 PM)

utils: dec_plmn(): remove redundant call

Change-Id: Ic95c3992ed57eb8fee952ec2dc7f092dd7689579
Vadim Yanitskiy at

#2967 (Mar 17, 2026, 8:15:44 PM)

sms: fix flags_construct in SMS_DELIVER

* field `tp_rp` appears at bit positions 7 and 5
** bit 7 should be `tp_rp` (Reply Path)
** bit 5 should be `tp_sri` (Status Report Indication)
* field `tp_lp` is completely missing
** should be at bit position 3

Change-Id: I0274849f0fa07281b5e050af429ffda7d249f9e8
Vadim Yanitskiy at

#2966 (Mar 17, 2026, 7:58:12 PM)

ts_31_102: EF_5G_PROSE_UIR: fix copy-pasted inner class name

Change-Id: I460e5ad70f35026d0d794271a4aef17323c14dfb
Vadim Yanitskiy at

#2965 (Mar 17, 2026, 7:40:45 PM)

global_platform: install_cap_parser: argument groups cannot be nested

pySim-shell currently does not work on systems with Python 3.14+:

  File ".../pysim/pySim/global_platform/__init__.py", line 868, in AddlShellCommands
    install_cap_parser_inst_prm_g_grp = install_cap_parser_inst_prm_g.add_argument_group()
  File "/usr/lib/python3.14/argparse.py", line 1794, in add_argument_group
    raise ValueError('argument groups cannot be nested')
  ValueError('argument groups cannot be nested')

The problem is that install_cap_parser creates a nested group inside
of mutually exclusive group.  argparse never supported group nesting
properly, so it has been deprecated since Python 3.11, and eventually
got removed in Python 3.14.

Remove group nesting, adjust the usage string, and implement the
mutual exclusiveness/inclusiveness manually in do_install_cap().

Change-Id: Idddf72d5a745345e134b23f2f01e0257d0667579
Vadim Yanitskiy at

#2964 (Mar 17, 2026, 7:23:16 PM)

global_platform: refactor gen_install_parameters()

gen_install_parameters() had contradictory logic: the outer guard
required all three arguments to be non-None/non-empty (making them
mutually inclusive), while the inner checks then treated each one
as optional.

Make each parameter independently optional (defaulting to None) and
remove the all-or-nothing check.  Simplify the function body to a
straightforward single-pass construction of system_specific_params.

Change-Id: I8756fb38016cdf0527fe2e21edb44381d1dc557f
Vadim Yanitskiy at

#2963 (Mar 17, 2026, 7:05:42 PM)

ota: OtaAlgo{Crypt,Auth}: fix algo_auth vs algo_crypt

* OtaAlgoCrypt.from_keyset() searches by `otak.algo_crypt`
  but the error message prints `otak.algo_auth`.  Should be
  `otak.algo_crypt` instead.

* OtaAlgoAuth.__init__() checks `algo_auth` but the error message
  prints `algo_crypt`.  Should be `otak.algo_auth` instead.

Change-Id: Ia636fffaeadc68e3f6d5b65d477e753834c95895
Vadim Yanitskiy at

#2962 (Mar 17, 2026, 6:48:14 PM)

global_platform: fix docstring for Scp03SessionKeys._get_icv()

Change-Id: I8983bc27f581295544360ba8b4ae1d28b3ea850f
Vadim Yanitskiy at

#2961 (Mar 17, 2026, 6:30:39 PM)

ara_m: fix exceptions not being raised properly

Exceptions are meant to be thrown/raised, not returned.

Change-Id: Id799c264447e22887edcd2dc7eb991cf0af1bbfc
Vadim Yanitskiy at

#2960 (Mar 17, 2026, 10:18:17 AM)

esim/http_json_api: allow URL rewriting

The URL used when HTTP requests are performed is defined statically
with the url_prefix passed to the constructor of JsonHttpApiClient
together with the path property in JsonHttpApiFunction.

For applications that require dynamic URLs there is no way to rewrite
the URL. Let's add a mechanism that allows API users to apply custom
URL reqriting rules by adding a rewrite_url method to
JsonHttpApiFunction. API users may then overload this method with a
custom implementation as needed.

Related: SYS#7918
Change-Id: Id2713a867079cc140517fe312189e5e2162608a5
pmaier@sysmocom.de at

#2959 (Mar 16, 2026, 3:31:36 PM)

esim/http_json_api: allow URL rewriting

The URL used when HTTP requests are performed is defined statically
with the url_prefix passed to the constructor of JsonHttpApiClient
together with the path property in JsonHttpApiFunction.

For applications that require dynamic URLs there is no way to rewrite
the URL. Let's add a mechanism that allows API users to apply custom
URL reqriting rules by adding a rewrite_url method to
JsonHttpApiFunction. API users may then overload this method with a
custom implementation as needed.

Related: SYS#7918
Change-Id: Id2713a867079cc140517fe312189e5e2162608a5
pmaier@sysmocom.de at

#2958 (Mar 16, 2026, 3:13:56 PM)

esim/http_json_api: allow URL rewriting

The URL used when HTTP requests are performed is defined statically
with the url_prefix passed to the constructor of JsonHttpApiClient
together with the path property in JsonHttpApiFunction.

For applications that require dynamic URLs there is no way to rewrite
the URL. Let's add a mechanism that allows API users to apply custom
URL reqriting rules by adding a reqrite_url method to
JsonHttpApiFunction. API users may then overload this method with a
custom implementation as needed.

Related: SYS#7918
Change-Id: Id2713a867079cc140517fe312189e5e2162608a5
pmaier@sysmocom.de at

#2957 (Mar 16, 2026, 2:56:27 PM)

ara_m: fix undefined variable used in a format-string

Change-Id: I310a5d461bae2b5e4d8e07097000b079c23aa0f6
Vadim Yanitskiy at

#2956 (Mar 16, 2026, 2:38:57 PM)

utils: dec_plmn(): remove redundant call

Change-Id: Ic95c3992ed57eb8fee952ec2dc7f092dd7689579
Vadim Yanitskiy at

#2955 (Mar 16, 2026, 2:20:59 PM)

ota: OtaAlgo{Crypt,Auth}: fix algo_auth vs algo_crypt

* OtaAlgoCrypt.from_keyset() searches by `otak.algo_crypt`
  but the error message prints `otak.algo_auth`.  Should be
  `otak.algo_crypt` instead.

* OtaAlgoAuth.__init__() checks `algo_auth` but the error message
  prints `algo_crypt`.  Should be `otak.algo_auth` instead.

Change-Id: Ia636fffaeadc68e3f6d5b65d477e753834c95895
Vadim Yanitskiy at

#2954 (Mar 16, 2026, 2:01:24 PM)

esim/saip: raise an exception properly

Change-Id: Ia3749c02120fdc16e556214d0461cbeca032447b
Vadim Yanitskiy at

#2953 (Mar 16, 2026, 1:43:56 PM)

global_platform: fix docstring for Scp03SessionKeys._get_icv()

Change-Id: I8983bc27f581295544360ba8b4ae1d28b3ea850f
Vadim Yanitskiy at

#2952 (Mar 16, 2026, 1:26:26 PM)

ts_31_102: EF_5G_PROSE_UIR: fix copy-pasted inner class name

Change-Id: I460e5ad70f35026d0d794271a4aef17323c14dfb
Vadim Yanitskiy at

#2951 (Mar 16, 2026, 1:09:04 PM)

global_platform: fix typo in SupportedTlsCipherSuitesForScp81

The attribute name is misspelled.  The BER-TLV infrastructure looks
for `_construct`; this typo means `SupportedTlsCipherSuitesForScp81`
will never decode its content.

Change-Id: I0f637951b0eeb7eca2a8b543baa737f216a935ed
Vadim Yanitskiy at

#2950 (Mar 16, 2026, 12:51:32 PM)

ts_31_102: fix description for EF_5GS3GPPLOCI

Change-Id: I9cf3adfce65090fedb3f0fd33c9b3d15a2c5fb8c
Vadim Yanitskiy at

#2949 (Mar 16, 2026, 12:33:58 PM)

ts_51_011: EF.EXT[6-7]: fix typo in desc

Change-Id: I93df1c9fd8a4d588ed7ed19ec2dc1d304412fc3d
Vadim Yanitskiy at

#2948 (Mar 16, 2026, 12:16:24 PM)

cdma_ruim: fix inaccurate comment for EF_AD

Change-Id: I71ea27fd30e44685ff35f49843072ca392995973
Vadim Yanitskiy at

#2947 (Mar 16, 2026, 11:58:57 AM)

global_platform: fix typo in ApplicationTemplate

The keyword argument should be `nested=`.  As written `ApplicationAID`
is silently ignored - `ApplicationTemplate` will not descend into its
nested TLVs.

Change-Id: If45dbb0c9b09fe53560d109957ce339267a9f2b0
Vadim Yanitskiy at

#2946 (Mar 16, 2026, 11:41:17 AM)

utils: DataObjectCollection.encode(): fix TypeError

`members_by_name` is a plain dictionary.  Calling it with `()` raises:

  TypeError: 'dict' object is not callable

Change-Id: I7e0c09aa7303f1506fe3a025fdc3779919dd0e6c
Vadim Yanitskiy at

#2945 (Mar 16, 2026, 11:06:26 AM)

sms: fix flags_construct in SMS_DELIVER

* field `tp_rp` appears at bit positions 7 and 5
** bit 7 should be `tp_rp` (Reply Path)
** bit 5 should be `tp_sri` (Status Report Indication)
* field `tp_lp` is completely missing
** should be at bit position 3

Change-Id: I0274849f0fa07281b5e050af429ffda7d249f9e8
Vadim Yanitskiy at

#2944 (Mar 16, 2026, 10:48:47 AM)

ara_m: fix exceptions not being raised properly

Exceptions are meant to be thrown/raised, not returned.

Change-Id: Id799c264447e22887edcd2dc7eb991cf0af1bbfc
Vadim Yanitskiy at

#2943 (Mar 16, 2026, 10:31:13 AM)

global_platform: fix store_data() returning last chunk only

The loop builds up `response` across multiple STORE DATA blocks,
but the function returns only `data` - the response from the
*last* block.  It should return the accumulated response instead.

Change-Id: I3e15c8004d1e366e8c3896e559656622f48bb1a2
Vadim Yanitskiy at

#2942 (Mar 16, 2026, 10:13:46 AM)

global_platform: fix s/GET/STORE/ DATA in docs

Both `do_store_data` and `store_data` have identical docstrings that
incorrectly describe the command as GET DATA.  Should be "STORE DATA".
Take a chance to fix missing space between `v2.3` and `Section`.

Change-Id: I33fc80ab8ca50fadc38217b0005eec6169c8e34e
Vadim Yanitskiy at

#2941 (Mar 16, 2026, 9:56:11 AM)

global_platform: make --install-parameters-* independently optional

gen_install_parameters() had contradictory logic: the outer guard
required all three arguments to be non-None/non-empty (making them
mutually inclusive), while the inner checks then treated each one
as optional.

Make each parameter independently optional (defaulting to None) and
remove the all-or-nothing guard from both the function and its caller.
Simplify the function body to a straightforward single-pass
construction of system_specific_params.

Change-Id: I8756fb38016cdf0527fe2e21edb44381d1dc557f
Vadim Yanitskiy at

#2940 (Mar 16, 2026, 12:25:41 AM)

personalization: add param_source.py, add batch.py

Implement pySim.esim.saip.batch.BatchPersonalization,
generating N eSIM profiles from a preset configuration.

Batch parameters can be fed by a constant, incrementing, random or from
CSV rows: add pySim.esim.saip.param_source.* classes to feed such input
to each of the BatchPersonalization's ConfigurableParameter instances.

Related: SYS#6768
Change-Id: I01ae40a06605eb205bfb409189fcd2b3a128855a
Neels Hofmeyr at

#2939 (Mar 16, 2026, 12:08:16 AM)

personalization: indicate default ParamSource per ConfigurableParameter

Add default_source class members pointing to ParamSource classes to all
ConfigurableParameter subclasses.

This is useful to automatically set up a default ParamSource for a given
ConfigurableParameter subclass, during user interaction to produce a
batch personalization.

For example, if the user selects a Pin1 parameter, a calling program can
implicitly set this to a RandomDigitSource, which will magically make it
work the way that most users need.

BTW, default_source and default_value can be combined to configure a
matching ParamSource instance:

  my_source = MyParam.default_source.from_str( MyParam.default_value )

Change-Id: Ie58d13bce3fa1aa2547cf3cee918c2f5b30a8b32
Neels Hofmeyr at

#2938 (Mar 15, 2026, 11:50:43 PM)

personalization: allow reading back multiple values from PES

Change-Id: Iecb68af7c216c6b9dc3add469564416b6f37f7b2
Neels Hofmeyr at

#2937 (Mar 15, 2026, 11:33:17 PM)

personalization: implement reading back values from a PES

Implement get_values_from_pes(), the reverse direction of apply_val():
read back and return values from a ProfileElementSequence. Implement for
all ConfigurableParameter subclasses.

Future: SdKey.get_values_from_pes() is reading pe.decoded[], which works
fine, but I07dfc378705eba1318e9e8652796cbde106c6a52 will change this
implementation to use the higher level ProfileElementSD members.

Implementation detail:

Implement get_values_from_pes() as classmethod that returns a generator.
Subclasses should yield all occurences of their parameter in a given
PES.

For example, the ICCID can appear in multiple places.
Iccid.get_values_from_pes() yields all of the individual values. A set()
of the results quickly tells whether the PES is consistent.

Rationales for reading back values:

This allows auditing an eSIM profile, particularly for producing an
output.csv from a batch personalization (that generated lots of random
key material which now needs to be fed to an HLR...).

Reading back from a binary result is more reliable than storing the
values that were fed into a personalization.
By auditing final DER results with this code, I discovered:
- "oh, there already was some key material in my UPP template."
- "all IMSIs ended up the same, forgot to set up the parameter."
- the SdKey.apply() implementations currently don't work, see
  I07dfc378705eba1318e9e8652796cbde106c6a52 for a fix.

Change-Id: I234fc4317f0bdc1a486f0cee4fa432c1dce9b463
Neels Hofmeyr at

#2936 (Mar 15, 2026, 11:15:46 PM)

personalization: indicate default ParamSource per ConfigurableParameter

Add default_source class members pointing to ParamSource classes to all
ConfigurableParameter subclasses.

This is useful to automatically set up a default ParamSource for a given
ConfigurableParameter subclass, during user interaction to produce a
batch personalization.

For example, if the user selects a Pin1 parameter, a calling program can
implicitly set this to a RandomDigitSource, which will magically make it
work the way that most users need.

BTW, default_source and default_value can be combined to configure a
matching ParamSource instance:

  my_source = MyParam.default_source.from_str( MyParam.default_value )

Change-Id: Ie58d13bce3fa1aa2547cf3cee918c2f5b30a8b32
Neels Hofmeyr at

#2935 (Mar 15, 2026, 10:58:21 PM)

personalization: allow reading back multiple values from PES

Change-Id: Iecb68af7c216c6b9dc3add469564416b6f37f7b2
Neels Hofmeyr at

#2934 (Mar 15, 2026, 10:40:49 PM)

personalization: implement reading back values from a PES

Implement get_values_from_pes(), the reverse direction of apply_val():
read back and return values from a ProfileElementSequence. Implement for
all ConfigurableParameter subclasses.

Future: SdKey.get_values_from_pes() is reading pe.decoded[], which works
fine, but I07dfc378705eba1318e9e8652796cbde106c6a52 will change this
implementation to use the higher level ProfileElementSD members.

Implementation detail:

Implement get_values_from_pes() as classmethod that returns a generator.
Subclasses should yield all occurences of their parameter in a given
PES.

For example, the ICCID can appear in multiple places.
Iccid.get_values_from_pes() yields all of the individual values. A set()
of the results quickly tells whether the PES is consistent.

Rationales for reading back values:

This allows auditing an eSIM profile, particularly for producing an
output.csv from a batch personalization (that generated lots of random
key material which now needs to be fed to an HLR...).

Reading back from a binary result is more reliable than storing the
values that were fed into a personalization.
By auditing final DER results with this code, I discovered:
- "oh, there already was some key material in my UPP template."
- "all IMSIs ended up the same, forgot to set up the parameter."
- the SdKey.apply() implementations currently don't work, see
  I07dfc378705eba1318e9e8652796cbde106c6a52 for a fix.

Change-Id: I234fc4317f0bdc1a486f0cee4fa432c1dce9b463
Neels Hofmeyr at

#2933 (Mar 15, 2026, 10:13:49 PM)

personalization: add param_source.py, add batch.py

Implement pySim.esim.saip.batch.BatchPersonalization,
generating N eSIM profiles from a preset configuration.

Batch parameters can be fed by a constant, incrementing, random or from
CSV rows: add pySim.esim.saip.param_source.* classes to feed such input
to each of the BatchPersonalization's ConfigurableParameter instances.

Related: SYS#6768
Change-Id: I01ae40a06605eb205bfb409189fcd2b3a128855a
Neels Hofmeyr at

#2932 (Mar 15, 2026, 3:41:13 PM)

esim/saip: raise an exception properly

Change-Id: Ia3749c02120fdc16e556214d0461cbeca032447b
Vadim Yanitskiy at

#2931 (Mar 15, 2026, 3:23:48 PM)

sms: fix flags_construct in SMS_DELIVER

* field `tp_rp` appears at bit positions 7 and 5
** bit 7 should be `tp_rp` (Reply Path)
** bit 5 should be `tp_sri` (Status Report Indication)
* field `tp_lp` is completely missing
** should be at bit position 3

Change-Id: I0274849f0fa07281b5e050af429ffda7d249f9e8
Vadim Yanitskiy at

#2930 (Mar 15, 2026, 3:06:18 PM)

ara_m: fix undefined variable used in a format-string

Change-Id: I310a5d461bae2b5e4d8e07097000b079c23aa0f6
Vadim Yanitskiy at

#2929 (Mar 15, 2026, 2:48:52 PM)

utils: dec_plmn(): remove redundant call

Change-Id: Ic95c3992ed57eb8fee952ec2dc7f092dd7689579
Vadim Yanitskiy at

#2928 (Mar 15, 2026, 2:31:25 PM)

ota: OtaAlgo{Crypt,Auth}: fix algo_auth vs algo_crypt

* OtaAlgoCrypt.from_keyset() searches by `otak.algo_crypt`
  but the error message prints `otak.algo_auth`.  Should be
  `otak.algo_crypt` instead.

* OtaAlgoAuth.__init__() checks `algo_auth` but the error message
  prints `algo_crypt`.  Should be `otak.algo_auth` instead.

Change-Id: Ia636fffaeadc68e3f6d5b65d477e753834c95895
Vadim Yanitskiy at

#2926 (Mar 15, 2026, 1:54:09 PM)

ts_51_011: EF.EXT[6-7]: fix typo in desc

Change-Id: I93df1c9fd8a4d588ed7ed19ec2dc1d304412fc3d
Vadim Yanitskiy at

#2925 (Mar 15, 2026, 1:36:37 PM)

utils: DataObjectCollection.encode(): fix TypeError

`members_by_name` is a plain dictionary.  Calling it with `()` raises:

  TypeError: 'dict' object is not callable

Change-Id: I7e0c09aa7303f1506fe3a025fdc3779919dd0e6c
Vadim Yanitskiy at

#2924 (Mar 15, 2026, 1:19:06 PM)

ts_31_102: EF_5G_PROSE_UIR: fix copy-pasted inner class name

Change-Id: I460e5ad70f35026d0d794271a4aef17323c14dfb
Vadim Yanitskiy at

#2923 (Mar 15, 2026, 1:01:41 PM)

global_platform: refactor gen_install_parameters()

Change-Id: I8756fb38016cdf0527fe2e21edb44381d1dc557f
Vadim Yanitskiy at

#2922 (Mar 15, 2026, 12:44:09 PM)

ara_m: fix exceptions not being raised properly

Exceptions are meant to be thrown/raised, not returned.

Change-Id: Id799c264447e22887edcd2dc7eb991cf0af1bbfc
Vadim Yanitskiy at

#2921 (Mar 15, 2026, 12:26:45 PM)

ts_31_102: fix description for EF_5GS3GPPLOCI

Change-Id: I9cf3adfce65090fedb3f0fd33c9b3d15a2c5fb8c
Vadim Yanitskiy at

#2920 (Mar 15, 2026, 12:24:21 PM)

ara_m: fix exceptions not being raised properly

Exceptions are meant to be thrown/raised, not returned.

Change-Id: Id799c264447e22887edcd2dc7eb991cf0af1bbfc
Vadim Yanitskiy at

#2919 (Mar 15, 2026, 12:06:59 PM)

global_platform: fix s/GET/STORE/ DATA in docs

Both `do_store_data` and `store_data` have identical docstrings that
incorrectly describe the command as GET DATA.  Should be "STORE DATA".
Take a chance to fix missing space between `v2.3` and `Section`.

Change-Id: I33fc80ab8ca50fadc38217b0005eec6169c8e34e
Vadim Yanitskiy at

#2918 (Mar 15, 2026, 12:04:33 PM)

ts_51_011: EF.EXT[6-7]: fix typo in desc

Change-Id: I93df1c9fd8a4d588ed7ed19ec2dc1d304412fc3d
Vadim Yanitskiy at

#2917 (Mar 15, 2026, 12:02:10 PM)

cdma_ruim: fix inaccurate comment for EF_AD

Change-Id: I71ea27fd30e44685ff35f49843072ca392995973
Vadim Yanitskiy at

#2916 (Mar 15, 2026, 11:59:45 AM)

ts_31_102: EF_5G_PROSE_UIR: fix copy-pasted inner class name

Change-Id: I460e5ad70f35026d0d794271a4aef17323c14dfb
Vadim Yanitskiy at

#2915 (Mar 15, 2026, 11:42:22 AM)

global_platform: fix docstring for Scp03SessionKeys._get_icv()

Change-Id: I8983bc27f581295544360ba8b4ae1d28b3ea850f
Vadim Yanitskiy at

#2914 (Mar 15, 2026, 11:40:02 AM)

sms: fix flags_construct in SMS_DELIVER

* field `tp_rp` appears at bit positions 7 and 5
** bit 7 should be `tp_rp` (Reply Path)
** bit 5 should be `tp_sri` (Status Report Indication)
* field `tp_lp` is completely missing
** should be at bit position 3

Change-Id: I0274849f0fa07281b5e050af429ffda7d249f9e8
Vadim Yanitskiy at

#2913 (Mar 15, 2026, 11:37:36 AM)

utils: DataObjectCollection.encode(): fix TypeError

`members_by_name` is a plain dictionary.  Calling it with `()` raises:

  TypeError: 'dict' object is not callable

Change-Id: I7e0c09aa7303f1506fe3a025fdc3779919dd0e6c
Vadim Yanitskiy at

#2912 (Mar 15, 2026, 11:35:09 AM)

ts_31_102: fix description for EF_5GS3GPPLOCI

Change-Id: I9cf3adfce65090fedb3f0fd33c9b3d15a2c5fb8c
Vadim Yanitskiy at

#2911 (Mar 15, 2026, 11:17:45 AM)

global_platform: fix store_data() returning last chunk only

The loop builds up `response` across multiple STORE DATA blocks,
but the function returns only `data` - the response from the
*last* block.  It should return the accumulated response instead.

Change-Id: I3e15c8004d1e366e8c3896e559656622f48bb1a2
Vadim Yanitskiy at

#2910 (Mar 15, 2026, 10:57:55 AM)

esim/saip: raise an exception properly

Change-Id: Ia3749c02120fdc16e556214d0461cbeca032447b
Vadim Yanitskiy at

#2909 (Mar 15, 2026, 10:40:37 AM)

global_platform: fix typo in SupportedTlsCipherSuitesForScp81

The attribute name is misspelled.  The BER-TLV infrastructure looks
for `_construct`; this typo means `SupportedTlsCipherSuitesForScp81`
will never decode its content.

Change-Id: I0f637951b0eeb7eca2a8b543baa737f216a935ed
Vadim Yanitskiy at

#2908 (Mar 15, 2026, 10:38:16 AM)

utils: dec_plmn(): remove redundant call

Change-Id: Ic95c3992ed57eb8fee952ec2dc7f092dd7689579
Vadim Yanitskiy at

#2907 (Mar 15, 2026, 10:35:50 AM)

ota: OtaAlgo{Crypt,Auth}: fix algo_auth vs algo_crypt

* OtaAlgoCrypt.from_keyset() searches by `otak.algo_crypt`
  but the error message prints `otak.algo_auth`.  Should be
  `otak.algo_crypt` instead.

* OtaAlgoAuth.__init__() checks `algo_auth` but the error message
  prints `algo_crypt`.  Should be `otak.algo_auth` instead.

Change-Id: Ia636fffaeadc68e3f6d5b65d477e753834c95895
Vadim Yanitskiy at

#2906 (Mar 15, 2026, 10:18:28 AM)

global_platform: install_cap_parser: argument groups cannot be nested

pySim-shell currently does not work on systems with Python 3.14+:

  File ".../pysim/pySim/global_platform/__init__.py", line 868, in AddlShellCommands
    install_cap_parser_inst_prm_g_grp = install_cap_parser_inst_prm_g.add_argument_group()
  File "/usr/lib/python3.14/argparse.py", line 1794, in add_argument_group
    raise ValueError('argument groups cannot be nested')
  ValueError('argument groups cannot be nested')

The problem is that install_cap_parser creates a nested group inside
of mutually exclusive group.  argparse never supported group nesting
properly, so it has been deprecated since Python 3.11, and eventually
got removed in Python 3.14.

Remove group nesting, adjust the usage string, and implement the
mutual exclusiveness/inclusiveness manually in do_install_cap().

Change-Id: Idddf72d5a745345e134b23f2f01e0257d0667579
Vadim Yanitskiy at

#2905 (Mar 15, 2026, 10:16:07 AM)

ara_m: fix undefined variable used in a format-string

Change-Id: I310a5d461bae2b5e4d8e07097000b079c23aa0f6
Vadim Yanitskiy at

#2904 (Mar 15, 2026, 10:13:35 AM)

global_platform: refactor gen_install_parameters()

Change-Id: I8756fb38016cdf0527fe2e21edb44381d1dc557f
Vadim Yanitskiy at

#2903 (Mar 15, 2026, 9:55:58 AM)

global_platform: fix typo in ApplicationTemplate

The keyword argument should be `nested=`.  As written `ApplicationAID`
is silently ignored - `ApplicationTemplate` will not descend into its
nested TLVs.

Change-Id: If45dbb0c9b09fe53560d109957ce339267a9f2b0
Vadim Yanitskiy at

#2902 (Mar 13, 2026, 5:31:34 PM)

docs/put_key: add tutorial that explains how to manage global platform keys

With the increased interest in using GlobalPlatform features of
UICC and eUICCs (OTA-SMS, applets, etc.), also comes an increased
interest in how the related GlobalPlatform keys can be managed
(key rotation, adding/removing keysets from/to a Security Domain).

Unfortunately, many aspects of this topic are not immediately
obvious for the average user. Let's add a tutorial that contains
some practical examples to shine some light on the topic.

Related: SYS#7881
Change-Id: I163dfedca3df572cb8442e9a4a280e6c5b00327e
pmaier@sysmocom.de at

#2901 (Mar 13, 2026, 5:13:55 PM)

docs/put_key: add tutorial that explains how to manage global platform keys

With the increased interest in using GlobalPlatform features of
UICC and eUICCs (OTA-SMS, applets, etc.), also comes an increased
interest in how the related GlobalPlatform keys can be managed
(key rotation, adding/removing keysets from/to a Security Domain).

Unfortunately, many aspects of this topic are not immediately
obvious for the average user. Let's add a tutorial that contains
some practical examples to shine some light on the topic.

Related: SYS#7881
Change-Id: I163dfedca3df572cb8442e9a4a280e6c5b00327e
pmaier@sysmocom.de at

#2900 (Mar 10, 2026, 3:42:08 PM)

pySim-prog/pySim-read: add pySimLogger and verbose cmdline argument

pySim-prog and pySim-read do not integrate the pySimLogger yet. As we
may add more debug output that should not be visible on normal use, we
should ensure that the pySimLogger is correctly set up.

Change-Id: Ia2fa535fd9ce4ffa301c3f5d6f98c1f7a4716c74
pmaier@sysmocom.de at

#2899 (Mar 10, 2026, 3:13:02 PM)

PySimLogger: add parameter to set initial log-level/verbosity

When we initialize a new PySimLogger, we always call the setup method
first and then use the set_verbose and set_level method to configure
the initial log level and the initial log verbosity. However, we
initialize the PySimLogger in all our programs the same way and we
end up with the same boilerplate code every time. Let's add a keyword
parameter to the setup method where we can pass our opts.verbose (bool)
parameter so that the setup method can do the work for the main program.

In case the caller wants a different default configuration he still can
call set_verbose and set_level methods as needed.

Change-Id: I4b8ef1e203186878910c9614a1d900d5759236a8
pmaier@sysmocom.de at

#2898 (Mar 10, 2026, 3:10:23 PM)

pySim-prog/pySim-read: add pySimLogger and verbose cmdline argument

pySim-prog and pySim-read do not integrate the pySimLogger yet. As we
may add more debug output that should not be visible on normal use, we
should ensure that the pySimLogger is correctly set up.

Change-Id: Ia2fa535fd9ce4ffa301c3f5d6f98c1f7a4716c74
pmaier@sysmocom.de at

#2897 (Mar 10, 2026, 2:54:53 PM)

pySim-shell/cosmetic: remove semicolon

Change-Id: I629bacd432491211b939fcd2bed554b44ef441bc
pmaier@sysmocom.de at

#2896 (Mar 10, 2026, 2:37:22 PM)

cdma_ruim: fix copy-pasted desc for EF.AD

Change-Id: I2338f35c21978dd6b8916c0abd57b94f5e087655
Vadim Yanitskiy at

#2895 (Mar 10, 2026, 2:20:12 PM)

global_platform: install_cap_parser: argument groups cannot be nested

pySim-shell currently does not work on systems with Python 3.14+:

  File ".../pysim/pySim/global_platform/__init__.py", line 868, in AddlShellCommands
    install_cap_parser_inst_prm_g_grp = install_cap_parser_inst_prm_g.add_argument_group()
  File "/usr/lib/python3.14/argparse.py", line 1794, in add_argument_group
    raise ValueError('argument groups cannot be nested')
  ValueError('argument groups cannot be nested')

The problem is that install_cap_parser creates a nested group inside
of mutually exclusive group.  argparse never supported group nesting
properly, so it has been deprecated since Python 3.11, and eventually
got removed in Python 3.14.

Remove group nesting, adjust the usage string, and implement the
mutual exclusiveness/inclusiveness manually in do_install_cap().

Change-Id: Idddf72d5a745345e134b23f2f01e0257d0667579
Vadim Yanitskiy at

#2894 (Mar 10, 2026, 11:58:14 AM)

pySim/transport: fix GET RESPONSE behaviour

The current behavior we implement in the method __send_apdu_T0 is
incomplete. Some details discussed in ETSI TS 102 221,
section 7.3.1.1.4, clause 4 seem to be not fully implemented. We
may also end up sending a GET RESPONSE in other APDU cases than
case 4 (the only case that uses the GET RESPONSE command).

Related: OS#6970
Change-Id: I26f0566af0cdd61dcc97f5f502479dc76adc37cc
pmaier@sysmocom.de at

#2893 (Mar 10, 2026, 11:42:40 AM)

contrib/csv-to_pgsl: explicitly set log level to INFO in non verbose mode

The current log level for PySimLogger currently is DEBUG. (The default
for verbose is False). Since those defaults may change over time, we
should conciously set what we want in verbose and non verbose mode, like
we already do in pySim-shell.

Change-Id: I4b8ef1e203186878910c9614a1d900d5759236a8
pmaier@sysmocom.de at

#2892 (Mar 10, 2026, 11:40:03 AM)

pySim-prog/pySim-read: add pySimLogger and verbose cmdline argument

pySim-prog and pySim-read do not integrate the pySimLogger yet. As we
may add more debug output that should not be visible on normal use, we
should ensure that the pySimLogger is correctly set up.

Change-Id: Ia2fa535fd9ce4ffa301c3f5d6f98c1f7a4716c74
pmaier@sysmocom.de at

#2891 (Mar 10, 2026, 11:04:11 AM)

pySim/transport: fix GET RESPONSE behaviour

The current behavior we implement in the method __send_apdu_T0 is
incomplete. Some details discussed in ETSI TS 102 221,
section 7.3.1.1.4, clause 4 seem to be not fully implemented. We
may also end up sending a GET RESPONSE in other APDU cases than
case 4 (the only case that uses the GET RESPONSE command).

Related: OS#6970
Change-Id: I26f0566af0cdd61dcc97f5f502479dc76adc37cc
pmaier@sysmocom.de at

#2142 (Mar 10, 2025, 1:01:16 PM)

[2/7] personalization: refactor ConfigurableParameter, Iccid, Imsi

Main points/rationales of the refactoring, details below:
1) common validation implementation
2) offer classmethods

The new features are optional, and will be heavily used by batch
personalization patches coming soon.

Implement Iccid and Imsi to use the new way, with a common abstract
DecimalParam implementation.

So far leave the other parameter classes working as they always did, to
follow suit in subsequent commits.

Details:

1) common validation implementation:
There are very common validation steps in the various parameter
implementations. It is more convenient and much more readable to
implement those once and set simple validation parameters per subclass.
So there now is a validate_val() classmethod, which subclasses can use
as-is to apply the validation parameters -- or subclasses can override
their cls.validate_val() for specialized validation.
(Those subclasses that this patch doesn't touch still override the
self.validate() instance method. Hence they still work as before this
patch, but don't use the new common features yet.)

2) offer stateless classmethods:
It is useful for...
- batch processing of multiple profiles (in upcoming patches) and
- user input validation
to be able to have classmethods that do what self.validate() and
self.apply() do, but do not modify any self.* members.
So far the paradigm was to create a class instance to keep state about
the value. This remains available, but in addition we make available the
paradigm of a singleton that is stateless (the classmethods).
Using self.validate() and self.apply() still work the same as before
this patch, i.e. via self.input_value and self.value -- but in addition,
there are now classmethods that don't touch self.* members.

Related: SYS#6768
Change-Id: I6522be4c463e34897ca9bff2309b3706a88b3ce8
Neels Hofmeyr at