29 Commits

Author SHA1 Message Date
Harald Welte
949c2a2d57 Use osmocom.construct.{Bytes,GreedyBytes} for hexstring input support
The upstream construct.{Bytes,GreedyBytes} only support bytes/bytearray
input data for the encoder, while the [newly-created]
osmocom.construct.{Bytes,GreedyBytes} support alternatively hex-string input.

This is important in the context of encoding construct-based types from
JSON, where our osmocom.utils.JsonEncoder will automatically convert any
bytes to hex-string, while re-encoding those hex-strings will fail prior
to this patch.

Change-Id: I1c8df6350c68aa408ec96ff6cd1e405ceb1a4fbb
Closes: OS#6774
2025-04-28 09:32:52 +02:00
Harald Welte
a3962b2076 Migrate over to using pyosmocom
We're creating a 'pyosmocom' pypi module which contains a number of core
Osmocom libraries / interfaces that are not specific to SIM card stuff
contained here.

The main modules moved in this initial step are pySim.tlv, pySim.utils
and pySim.construct. utils is split, not all of the contents is
unrelated to SIM Cards.  The other two are moved completely.

Change-Id: I4b63e45bcb0c9ba2424dacf85e0222aee735f411
2024-09-03 21:57:47 +02:00
Harald Welte
0c022944ff pySim.apdu.global_platform: Decode the INSTALL command parameters
Change-Id: I1c323c1cb1be504c6ad5b7efb0fa85d87eaa8cf7
2024-07-26 08:38:17 +02:00
Harald Welte
87b4f99a90 pySim.apdu: Get rid of HexAdapter
In the past, we always wrapped a HexAdapter around bytes-like data in
order to make sure it's printed as hex-digits.  However, now that we are
doing JSON output it's much easier to let the pySim.utils.JsonEncoder
take care of this in a generic way.

We should do a similar migration all over pySim (pySim-shell,
filesystem, etc.) - but for now only do it in the low-hanging fruit of
pySim-trace aka pySim.apdu

Change-Id: I0cde40b2db08b4db9c10c1ece9ca6fdd42aa9154
2024-07-26 06:20:46 +00:00
Harald Welte
699b49ef1b pySim.apdu.ts_102_222: APDU decoding for administrative commands
Change-Id: I77c97221da19e1a67d96f7cfb69785baefc675c0
2024-07-24 10:37:05 +02:00
Harald Welte
d93d774dcc pySim.apdu: Fix APDU CLA matching
The cla values as hex strings must be compared in case insensitive manner

Change-Id: I890bc385d6209e6cfe9b0c38bd9deee7ae50e5f5
2024-07-19 18:24:29 +02:00
Harald Welte
289d2343fa pySim.apdu: Refactor cmd_to_dict() method
Let's factor out the "automatic processing using _tlv / _construct" as a
separate method.  This way we enable a derived class to first call that
automatic processing method, and then amend its output in a second step.

Change-Id: I1f066c0f1502020c88d99026c25bf2e283c3b4f5
2024-07-19 18:23:36 +02:00
Harald Welte
2eea70f6bc pySim.apdu.ts_102_221: Decode FETCH and TERMINAL RESPONSE body
This gives a meaningful decode during pySim-trace.

Change-Id: Ifa410e1fefc25e87ffa8e3a2230af80180a36a18
2024-06-08 18:38:22 +02:00
Harald Welte
f22637f151 pySim.apdu.ts_102_221: Decode the ENVELOPE command body using pySim.cat TLV
This will decode the ENVELOPE body in pySim-trace further.

Before:

00 ENVELOPE                                             -        9000 {'p1': 0, 'p2': 0, 'cmd': 'd14682028381060291978b3c40048111227ff6407070611535002d02700000281516011212000001eae1bd578fa25791898128811b2206cc71639ca292ec2526da8aef4273d2fe2e', 'rsp': '027100001f0a00000100000001200000ab12800101230d08a0000001510000000f829000'}

After:

00 ENVELOPE                                             -        9000 {'p1': 0, 'p2': 0, 'cmd': [{'smspp_download': [{'device_identities': {'source_dev_id': 'network', 'dest_dev_id': 'uicc'}}, {'address': {'ton_npi': 145, 'call_number': '79'}}, {'sms_tpdu': {'tpdu': '40048111227ff6407070611535002d02700000281516011212000001eae1bd578fa25791898128811b2206cc71639ca292ec2526da8aef4273d2fe2e'}}]}], 'rsp': '027100001f0a00000100000001200000ab12800101230d08a0000001510000000f829000'}

Change-Id: I5ecdbe0b5fa8856cb723569896b73cd49778ed5f
2024-06-08 18:38:22 +02:00
Harald Welte
33a6daee6d pySim.apdu: Allow TLV based decoders for APDU command and response body
So far we only supported construct.

Change-Id: Ibb80d328c9a1f464aa5338ca0ca1d6bfb00734e1
2024-06-08 18:38:22 +02:00
Harald Welte
f2322774c7 pylint: filesystem.py
pySim/filesystem.py:823:0: C0325: Unnecessary parens after 'if' keyword (superfluous-parens)
pySim/filesystem.py:849:0: C0325: Unnecessary parens after 'if' keyword (superfluous-parens)
pySim/filesystem.py:43:0: W0401: Wildcard import pySim.exceptions (wildcard-import)
pySim/filesystem.py:74:45: C0121: Comparison 'fid == None' should be 'fid is None' (singleton-comparison)
pySim/filesystem.py:94:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
pySim/filesystem.py:100:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
pySim/filesystem.py:149:8: W0105: String statement has no effect (pointless-string-statement)
pySim/filesystem.py:170:11: C0121: Comparison 'self.parent == None' should be 'self.parent is None' (singleton-comparison)
pySim/filesystem.py:283:8: R1705: Unnecessary "elif" after "return", remove the leading "el" from "elif" (no-else-return)
pySim/filesystem.py:309:8: W0246: Useless parent or super() delegation in method '__init__' (useless-parent-delegation)
pySim/filesystem.py:314:15: C0117: Consider changing "not 'fid' in kwargs" to "'fid' not in kwargs" (unnecessary-negation)
pySim/filesystem.py:317:24: R1735: Consider using '{}' instead of a call to 'dict'. (use-dict-literal)
pySim/filesystem.py:418:11: C0121: Comparison 'name == None' should be 'name is None' (singleton-comparison)
pySim/filesystem.py:427:11: C0121: Comparison 'sfid == None' should be 'sfid is None' (singleton-comparison)
pySim/filesystem.py:452:28: R1735: Consider using '{}' instead of a call to 'dict'. (use-dict-literal)
pySim/filesystem.py:508:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
pySim/filesystem.py:531:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
pySim/filesystem.py:576:8: W0246: Useless parent or super() delegation in method '__init__' (useless-parent-delegation)
pySim/filesystem.py:599:19: W0612: Unused variable 'sw' (unused-variable)
pySim/filesystem.py:609:19: W0612: Unused variable 'sw' (unused-variable)
pySim/filesystem.py:620:19: W0612: Unused variable 'sw' (unused-variable)
pySim/filesystem.py:633:28: W0612: Unused variable 'sw' (unused-variable)
pySim/filesystem.py:642:41: W0613: Unused argument 'opts' (unused-argument)
pySim/filesystem.py:644:24: W0612: Unused variable 'sw' (unused-variable)
pySim/filesystem.py:696:8: R1705: Unnecessary "elif" after "return", remove the leading "el" from "elif" (no-else-return)
pySim/filesystem.py:723:8: R1705: Unnecessary "elif" after "return", remove the leading "el" from "elif" (no-else-return)
pySim/filesystem.py:749:8: R1705: Unnecessary "elif" after "return", remove the leading "el" from "elif" (no-else-return)
pySim/filesystem.py:777:8: R1705: Unnecessary "elif" after "return", remove the leading "el" from "elif" (no-else-return)
pySim/filesystem.py:797:8: W0246: Useless parent or super() delegation in method '__init__' (useless-parent-delegation)
pySim/filesystem.py:822:23: W0612: Unused variable 'sw' (unused-variable)
pySim/filesystem.py:838:19: W0612: Unused variable 'sw' (unused-variable)
pySim/filesystem.py:844:34: W0613: Unused argument 'opts' (unused-argument)
pySim/filesystem.py:848:23: W0612: Unused variable 'sw' (unused-variable)
pySim/filesystem.py:866:23: W0612: Unused variable 'sw' (unused-variable)
pySim/filesystem.py:878:19: W0612: Unused variable 'sw' (unused-variable)
pySim/filesystem.py:893:28: W0612: Unused variable 'sw' (unused-variable)
pySim/filesystem.py:910:24: W0612: Unused variable 'sw' (unused-variable)
pySim/filesystem.py:967:8: R1705: Unnecessary "elif" after "return", remove the leading "el" from "elif" (no-else-return)
pySim/filesystem.py:995:8: R1705: Unnecessary "elif" after "return", remove the leading "el" from "elif" (no-else-return)
pySim/filesystem.py:1023:8: R1705: Unnecessary "elif" after "return", remove the leading "el" from "elif" (no-else-return)
pySim/filesystem.py:1051:8: R1705: Unnecessary "elif" after "return", remove the leading "el" from "elif" (no-else-return)
pySim/filesystem.py:1114:8: R1705: Unnecessary "elif" after "return", remove the leading "el" from "elif" (no-else-return)
pySim/filesystem.py:1141:8: R1705: Unnecessary "elif" after "return", remove the leading "el" from "elif" (no-else-return)
pySim/filesystem.py:1167:8: R1705: Unnecessary "elif" after "return", remove the leading "el" from "elif" (no-else-return)
pySim/filesystem.py:1194:8: R1705: Unnecessary "elif" after "return", remove the leading "el" from "elif" (no-else-return)
pySim/filesystem.py:1226:8: W0246: Useless parent or super() delegation in method '__init__' (useless-parent-delegation)
pySim/filesystem.py:1236:19: W0612: Unused variable 'sw' (unused-variable)
pySim/filesystem.py:1239:35: W0613: Unused argument 'opts' (unused-argument)
pySim/filesystem.py:1252:19: W0612: Unused variable 'sw' (unused-variable)
pySim/filesystem.py:1263:19: W0612: Unused variable 'sw' (unused-variable)
pySim/filesystem.py:1315:24: R1735: Consider using '{}' instead of a call to 'dict'. (use-dict-literal)
pySim/filesystem.py:35:0: C0411: standard import "import argparse" should be placed before "import cmd2" (wrong-import-order)
pySim/filesystem.py:37:0: C0411: standard import "from typing import cast, Optional, Iterable, List, Dict, Tuple, Union" should be placed before "import cmd2" (wrong-import-order)
pySim/filesystem.py:27:0: W0611: Unused import code (unused-import)
pySim/filesystem.py:34:0: W0611: Unused with_argparser imported from cmd2 (unused-import)
pySim/filesystem.py:41:0: W0611: Unused i2h imported from pySim.utils (unused-import)
pySim/filesystem.py:41:0: W0611: Unused Hexstr imported from pySim.utils (unused-import)
pySim/filesystem.py:44:0: W0611: Unused js_path_find imported from pySim.jsonpath (unused-import)
pySim/filesystem.py:43:0: W0614: Unused import(s) NoCardError, ProtocolError, ReaderError and SwMatchError from wildcard import of pySim.exceptions (unused-wildcard-import)

Change-Id: I94e1f5791e9fc34a60d0254978a35fd6ab2ff8d7
2024-02-05 17:51:59 +01:00
Harald Welte
a5630dc45c pylint: apdu/ts_102_221.py
pySim/apdu/ts_102_221.py:60:16: R1724: Unnecessary "else" after "continue", remove the "else" and de-indent the code inside it (no-else-continue)
pySim/apdu/ts_102_221.py:107:16: W0107: Unnecessary pass statement (unnecessary-pass)
pySim/apdu/ts_102_221.py:294:8: R1703: The if statement can be replaced with 'return bool(test)' (simplifiable-if-statement)
pySim/apdu/ts_102_221.py:294:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
pySim/apdu/ts_102_221.py:299:31: W0613: Unused argument 'lchan' (unused-argument)
...
pySim/apdu/ts_102_221.py:389:8: R1705: Unnecessary "elif" after "return", remove the leading "el" from "elif" (no-else-return)
pySim/apdu/ts_102_221.py:421:8: R1705: Unnecessary "elif" after "return", remove the leading "el" from "elif" (no-else-return)
pySim/apdu/ts_102_221.py:425:12: R1705: Unnecessary "elif" after "return", remove the leading "el" from "elif" (no-else-return)
pySim/apdu/ts_102_221.py:438:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
pySim/apdu/ts_102_221.py:26:0: C0411: standard import "from typing import Optional, Dict, Tuple" should be placed before "from construct import GreedyRange, Struct" (wrong-import-order)

Change-Id: Id5caac8da4c965dbaf88d624cdc9dcc8fc168b8c
2024-02-05 09:55:56 +01:00
Harald Welte
9ef65099d2 pylint: apdu/__init__.py
pySim/apdu/__init__.py:41:0: W0105: String statement has no effect (pointless-string-statement)
pySim/apdu/__init__.py:55:4: C0204: Metaclass class method __new__ should have 'mcs' as first argument (bad-mcs-classmethod-argument)
pySim/apdu/__init__.py:187:8: R1705: Unnecessary "elif" after "return", remove the leading "el" from "elif" (no-else-return)
pySim/apdu/__init__.py:200:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
pySim/apdu/__init__.py:208:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
pySim/apdu/__init__.py:216:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
pySim/apdu/__init__.py:224:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
pySim/apdu/__init__.py:239:11: C0117: Consider changing "not 'p1' in self.cmd_dict" to "'p1' not in self.cmd_dict" (unnecessary-negation)
pySim/apdu/__init__.py:295:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
pySim/apdu/__init__.py:313:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
pySim/apdu/__init__.py:416:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
pySim/apdu/__init__.py:429:12: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
pySim/apdu/__init__.py:455:8: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
pySim/apdu/__init__.py:31:0: C0411: standard import "import typing" should be placed before "from termcolor import colored" (wrong-import-order)
pySim/apdu/__init__.py:32:0: C0411: standard import "from typing import List, Dict, Optional" should be placed before "from termcolor import colored" (wrong-import-order)

Change-Id: I5657912df474f3ed0e277458a8eb33e28aeb2927
2024-02-05 09:53:21 +01:00
Harald Welte
0930bcbbb7 pylint: apdu/ts_31_102.py
pySim/apdu/ts_31_102.py:12:0: W0401: Wildcard import construct (wildcard-import)
pySim/apdu/ts_31_102.py:38:0: W0404: Reimport 'ApduCommand' (imported line 18) (reimported)
pySim/apdu/ts_31_102.py:38:0: W0404: Reimport 'ApduCommandSet' (imported line 18) (reimported)

Change-Id: I191147af95142adcd7d768d7dae6480b0c7513fc
2024-02-05 09:53:16 +01:00
Harald Welte
e55fcf66bf Be more conservative in our imports
Try to avoid '*' from anything into various modules, polluting the
namespace.

Change-Id: Iba749d18e1863ded88ba2d2183e2e8d718b2d612
2024-02-04 21:27:00 +01:00
Harald Welte
cfa62cb95b Allow logger to do lazy evaluation of format strings
Change-Id: I39d26cdd5b85a61a06fd8c7a9d0a046e398819bd
2024-01-08 12:10:11 +00:00
Philipp Maier
162ba3af3e pySim-trace: mark card reset in the trace
The trace log currently does not contain any information about card
resets. This makes the trace difficult to follow. Let's use the
CardReset object to display the ATR in the trace.

Related: OS#6094
Change-Id: Ia550a8bd2f45d2ad622cb2ac2a2905397db76bce
2023-07-28 10:14:19 +02:00
Philipp Maier
7d86fe1d8a apdu/ts_102_221: extract channel number from dict before calling del_lchan
When the method del_lchan is called, closed_channel_nr still contains a dict
that contains the channel number under the key 'logical_channel_number'.
This will lead to an exception. We must extact the channel number from
the dict before we can use it with del_lchan. (See also
created_channel_nr)

Related: OS#6094
Change-Id: I399856bc227f17b66cdb4158a69a35d50ba222a7
2023-07-20 15:50:16 +00:00
Harald Welte
531894d386 move Runtime{State,Lchan} from pySim.filesystem to new pySim.runtime
Those two are really separate concepts, so let's keep them in separate
source code files.

Change-Id: I9ec54304dd8f4a4cba9487054a8eb8d265c2d340
2023-07-12 22:05:14 +02:00
Harald Welte
1de62c41d7 pySim/apdu/ts_31_102.py: Add Rel17 5G NSWO context for GET IDENTITY
Change-Id: I6ce5848ca4cf04430be7767e9cb2d18f4c5a5531
2023-06-07 11:14:07 +02:00
Harald Welte
f6b37af721 Prepare for decoding/encoding records differently based on record number
In their infinite wisdom, the authors of the EIRENE FFFIS for GSM-R SIM
cards invented yet a new way of encoding data in SIM card files: The
first record of a file may be encoded differently than further records
of files.

Let's add the required infrastructure to pySim so that the encode and
decode methods for record-oriented files get passed in the current
record number.

Change-Id: I02d6942016dd0631b21d1fd301711c13cb27962b
Related: OS#5784
2023-01-24 20:03:02 +01:00
Harald Welte
bc7437d3b6 pySim-trace: Also consider SW 91xx as successful
Change-Id: I9e4170721be30342bdce7fb4beeefd1927263ca6
2023-01-24 13:50:51 +01:00
Harald Welte
7489947046 pySim-trace: Fix missing MANAGE CHANNEL decode
old output:

00 MANAGE CHANNEL 01       9110

new output:

00 MANAGE CHANNEL 01       9110 {'mode': 'open_channel', 'created_channel': 1}

Change-Id: Iac5b24c14d2b68d526ab347462b72548b8731b30
2023-01-24 13:50:51 +01:00
Harald Welte
93c34aac89 apdu/ts_102_221: SELECT: allow select of SELF
While in the pySim-shell, it's useful to filter the currently selected
file from the choice of available files for select, this doesn't apply
for the tracing case: It's perfectly valid for the UE to SELECT the
file that's already selected right now.  The operation basically
becomes equivalent to a STATUS.

Change-Id: I1a20fb3ba70426333ac34448c6cb782c51363965
2022-07-25 14:25:11 +02:00
Harald Welte
dcc689d9c4 apdu/ts_102_221: SELECT: allow select of parent/ancestor DFs
We need to pass the 'PARENT' flag to get_selectables() to be able
to track SELECT on any of the parent/ancestor DF FID.

Change-Id: Ia7ac627d5edccb97160c90688d720d887fad6ec7
2022-07-25 14:25:11 +02:00
Harald Welte
8e9c844130 apdu/ts_102_221: Fix SELECT of 3f00
In order to be able to explicitly select the MF via 3f00,
we need to pass the 'MF' to get_selectables(), so the record
is included in the list of selectable files from the current
working directory.

Change-Id: I27085896142fe547a6e93e01e63e59bbc65c8b8a
2022-07-24 11:56:35 +02:00
Harald Welte
498361f3b5 apdu/ts_102_221: Implement SELECT case "df_ef_or_mf_by_file_id"
This was [sadly] simply missing from the implementation so far.

Change-Id: I7bbd13ce29f5adc1ca3ca01bffabbe02dd17db20
2022-07-24 11:56:35 +02:00
Harald Welte
c61fbf4daa pySim-trace: Support SELECT with empty response body
If the modem/UE doesn't ask for the FCP to be returned, a SELECT
can exit with 9000 and no response body.  Don't crash in that case.

Change-Id: I66788717bec921bc54575e60f3f81adc80584dbc
2022-07-24 09:46:11 +02:00
Harald Welte
21caf32e3d Introduce APDU/TPDU trace decoder
This introduces a new pySim.apdu module hierarchy, which contains
classes that represent TPDU/APDUs as exchanged between
SIM/UICC/USIM/ISIM card and UE.

It contains instruction level decoders for SELECT, READ BINARY and
friends, and then uses the pySim.filesystem.Runtime{Lchan,State} classes
to keep track of the currently selected EF/DF/ADF for each logical
channel, and uses the file-specific decoder classes of pySim to decode
the actual file content that is being read or written.

This provides a much more meaningful decode of protocol traces than
wireshark will ever be able to give us.

Furthermore, there's the new pySim.apdu_source set of classes which
provides "input plugins" for obtaining APDU traces in a variety of
formats.  So far, GSMTAP UDP live capture and pyshark based RSPRO
live and pcap file reading are imlpemented.

Change-Id: I862d93163d495a294364168f7818641e47b18c0a
Closes: OS#5126
2022-07-23 12:18:57 +02:00