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.
Commit
ae656c66a3b3a382644ca895d808bca0dad9f2b2
by laforge
personalization: refactor AlgorithmID, K, Opc
Refactor AlgorithmID, K, Opc to the new ConfigurableParameter implementation style.
K and Opc use a common abstract BinaryParam.
Note from the future: AlgorithmID so far takes "raw" int values, but will turn to be an "enum" parameter with predefined meaningful strings in I71c2ec1b753c66cb577436944634f32792353240
Commit
429b12c8b5064f3abc7ca4c1d748cd5544d15b29
by laforge
pySim-trace: pySim.apdu_source.stdin_hex
This introduces an "APDU source" for pySim-trace which enables the decoding of APDUs that are copy+pasted from elsewhere, for example APDU logs in text form created by proprietary tools, or to decode personalization scripts or the like.
Commit
e0a9e73267f18fed1d81874938f5e2831afd12e6
by laforge
http_json_api: Only require Content-Type if response body is non-empty
If there is an empty body returned, such as in the case of the response to an es9p notification, then it is of course also legal to not set the content-type header.
This patch fixes an exception when talking to certain SM-DP+ with es9p_client.py:
DEBUG:pySim.esim.http_json_api:HTTP RSP-STS: [204] hdr: {'X-Admin-Protocol': 'gsma/rsp/v2.5.0', 'Date': 'Wed, 28 Jan 2026 18:26:39 GMT', 'Server': 'REDACTED'} DEBUG:pySim.esim.http_json_api:HTTP RSP: b'' {'X-Admin-Protocol': 'gsma/rsp/v2.5.0', 'Date': 'Wed, 28 Jan 2026 18:26:39 GMT', 'Server': 'REDACTED'} <Response [204]> Traceback (most recent call last): File "gprojects/git/pysim/es9p/../contrib/es9p_client.py", line 315, in <module> c.do_notification() ~~~~~~~~~~~~~~~~~^^ File "projects/git/pysim/es9p/../contrib/es9p_client.py", line 159, in do_notification res = self.peer.call_handleNotification(data) File "projects/git/pysim/contrib/pySim/esim/es9p.py", line 174, in call_handleNotification return self.handleNotification.call(data) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^ File "projects/git/pysim/contrib/pySim/esim/http_json_api.py", line 335, in call if not response.headers.get('Content-Type').startswith(req_headers['Content-Type']): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AttributeError: 'NoneType' object has no attribute 'startswith'
Commit
15691233e1b5c1f151b36ca199f2f49581d049cd
by laforge
tests/pySim-smpp2sim_test: add integration test
At the moment pySim.ota codebase is not covered by any of the integration tests (we have only normal unittests so far). To increase the test coverage, let's add an integration test that sends exchanges an RFM OTA-SMS with a real-world card.
However, there is no tool avaliable that can be used as an SMPP client for pySim-smpp2sim yet. Let's use smpp_ota_apdu2.py on laforge/ota to develop a tool that we can use to exchange SMS-TPDUs that contain remote APDU scripts (RFM/RAM).
Finally let's use the tool we have created as a basis to create an integration test that exchanges an SMS-TPDU with the RFM application of a sysmoISIM-SJA5 card. The testcase shall pass when we get the expected response from the card.
(normally KID index and KIC index should be the same since mixing keys is a concidered as a security violation. However, in this tool we want to allow users to specify different indexes for KIC and KIC so that they can make tests to make sure their cards correctly reject mixed up key indexes)
contrib/smpp-ota-tool: warn about mixed up KIC/KIC indexes
Cards usually have multiple sets of KIC, KID (and KIK). The keys are selected through an index. However, mixing keys from different sets is concidered as a security violation and cards should reject such configurations.
Let's print a warning to make users aware that something is off.