Commit Graph

1086 Commits

Author SHA1 Message Date
Philipp Maier
a3469bc03b card_key_provider: add PostgreSQL support
The Card Key Provider currently only has support for CSV files
as input. Unfortunately using CSV files does not scale very well
when the card inventory is very large and continously updated.
In this case a centralized storage in the form of a database
is the more suitable approach.

This patch adds PostgreSQL support next to the existing CSV
file support. It also adds an importer tool to import existing
CSV files into the database.

Change-Id: Icba625c02a60d7e1f519b506a46bda5ded0537d3
Related: SYS#7725
2025-12-18 15:59:31 +01:00
Philipp Maier
c118012fb9 pysim/log: also accept ANSI strings to specify the log message colors
the PySimLogger class currently only accepts cmd2 color enum values.
This is what we need for pySim-shell.py. However, in case we want to
use the PySimLogger in stand-alone programs that do not use cmd2, this
is a bit bulky. Let's add some flexibility to PySimLogger, so that we
can specify the colors as raw ANSI strings as well.

Change-Id: I93543e19649064043ae8323f82ecd8c423d1d921
Related: SYS#7725
2025-12-18 15:59:01 +01:00
Harald Welte
45bffb53f9 pySim.ts_51_011.EF_SMSP: Also permit UCS2 for the alpha_id
TS 51.011 Section 10.5.6 refers to clause 10.5.1 (EF.ADN),
and the latter permits UCS2 in addition to 7-bit GSM alphabet.

Change-Id: If10b3d6d8b34ece02dc0350ca9ea9c3f8fbf3c9e
2025-12-16 16:31:14 +01:00
Harald Welte
cc15b2b4c3 ts_51_011.EF_SMSP: Use integer division during encode
Otherwise we might compute float values and fail encoding like this:

> construct.core.FormatFieldError: Error in path (building) -> tp_vp_minutes
> struct '>B' error during building, given value 169.0

Change-Id: I989669434c7ddee9595ee81a0822f9966907a844
2025-12-16 16:31:12 +01:00
Harald Welte
11dfad88e6 pySim.esim.saip: Fix compatibility with pytohn < 3.11
In python up to 3.10, the byteorder argument of the int.to_bytes()
method was mandatory, even if the length of the target byte sequence
is 1 and there factually is no byteorder.

https://docs.python.org/3.10/library/stdtypes.html#int.to_bytes
vs
https://docs.python.org/3.11/library/stdtypes.html#int.to_bytes

See also: https://discourse.osmocom.org/t/assistance-required-with-saip-pysim-tool-error-while-adding-applets-to-exiting-upp-der/2413/2

Change-Id: I8ba29d42c8d7bf0a36772cc3370eff1f6afa879f
2025-12-14 13:58:34 +01:00
Harald Welte
572a81f2af pySim.runtime: Fix file selection by upper case hex FID
When trying to remove a file (e.g. DF.5G_ProSe, 5FF0),
there seems to be a case sensitive check when checking for the dict:
pySim/runtime.py: get_file_for_filename():

478          def get_file_for_filename(self, name: str):
479              """Get the related CardFile object for a specified filename."""
480              sels = self.selected_file.get_selectables()
481              return sels[name]

The dict sels contains 5ff0, but not 5FF0.
The type of argument name is str. So a case sensitive check will be used.

Change-Id: Idd0db1f4bbd3ee9eec20f5fd0f4371c2882950cd
Closes: OS#6898
2025-12-10 13:34:27 +00:00
Harald Welte
c07ecbae52 pySim.esim.saip: Hex representation of SecurityDomainKey
Let's print the key_usage_qualifier in hexadecimal notation (more compact)

Change-Id: Ic9a92d53d73378eafca1760dd8351215bce1157a
2025-12-09 16:23:49 +00:00
Alexander Couzens
e20f9e6cdf ts_102_221: EF.ARR: fix read_arr_record
`read_arr_record 1` failed with an AttributeError exception
because RECORD_NR must be all caps.

Change-Id: If44f9f2271293d3063f6c527e5a68dcfaeb5942e
2025-12-04 15:32:16 +01:00
Philipp Maier
c2fb84251b card_key_provider: add missing type annotation
Related: SYS#7725
Change-Id: I45751d2b31976c04c03006d8baa195eef2576b4f
2025-11-21 17:49:09 +01:00
Philipp Maier
61541e7502 card_key_provider: refactor code and optimize out get_field method
The method get_field in the base class can be optimized out. This
also allows us to remove code dup in the card_key_provider_get_field
function.

Let's also fix the return code behavior. A get method in a
CardKeyProvider implementation should always return None in case
nothing is found. Also it should not crash in that case. This will
allow the card_key_provider_get function to move on to the next
CardKeyProvider. In case no CardKeyProvider yields any results, an
exception is appropriate since it is pointless to continue execution
with "None" as key material.

To make the debugging of problems easier, let's also print some debug
messages that inform the user what key/value pair and which
CardKeyProvider was queried. This will make it easier to investigate
in case an expected result was not found.

Related: SYS#7725
Change-Id: I4d6367b8eb057e7b2c06c8625094d8a1e4c8eef9
2025-11-21 17:49:09 +01:00
Philipp Maier
579214c4d0 card_key_provider: remove method _verify_get_data from base class
The method _verify_get_data was intended to be used to verify the
user input before it further processed but ended up to be a simple
check that only checks the name of the key column very basically.

Unfortunately it is difficult to generalize the check code as the
concrete implementation of those checks is highly format dependent.
With the advent of eUICCs, we now have two data formats with
different lookup keys, so a static list with valid lookup keys is
also no longer up to the task.

After all it makes not much sense to keep this method, so let's
remove it.

(From the technical perspective, the key column is not limitied to
any specif field. In theory it would even be possible to use the KI
as lookup key as well, even though it would not make sense in
practice)

Related: SYS#7725
Change-Id: Ibf5745fb8a4f927397adff33900731524715d6a9
2025-11-21 17:49:09 +01:00
Philipp Maier
a6ca5b7cd1 card_key_provider: remove unnecessary class property definitions
The two properties csv_file and csv_filename are defined by the
constructor anyway, let's remove the declaration in the class body
because it is not needed.

Change-Id: Ibbe8e17b03a4ba0041c0e9990a5e9614388d9c03
2025-11-21 17:49:09 +01:00
Philipp Maier
bcca2bffc2 card_key_provider: rename parameter filename to csv_filename
let's rename the parameter filename to csv_filename to make it
more clear to what kind of file this parameter refers.

Change-Id: Id5b7c61b5e72fb205e30d2787855b2c276840a7b
2025-11-21 17:49:09 +01:00
Philipp Maier
e80f96cc3b card_key_provider: use case-insensitive field names
It is common in CSV files that the columns have uppercase names, so we
have adopted this scheme when we started using the card_key_provider.

This also means that the API of the card_key_provider_get() and
card_key_provider_get_field() function now implicitly requires
uppercase field names like 'ICCID', 'ADM1', etc.

Unfortunately this may be unreliable, so let's convert the field
names to uppercase as soon as we receive them. This makes the API
case-insensitive and gives us the assurance that all field names
we ever work with are in uppercase.

Related: SYS#7725
Change-Id: I9d80752587e2ccff0963c10abd5a2f42f5868d79
2025-11-21 17:49:09 +01:00
Philipp Maier
4550574e03 card_key_provider: separate and refactor CSV column encryption
The CardKeyProviderCsv class implements a column decryption scheme
where columns are protected using a transport key. The CSV files
are enrcypted using contrib/csv-encrypt-columns.py.

The current implementation has two main problems:

- The decryption code in CardKeyProviderCsv is not specific to CSV files.
  It could be re-used in other formats, for example to decrypt columns
  (fields) red from a database. So let's split the decryption code in a
  separate class.

- The encryption code in csv-encrypt-columns.py accesses methods and
  properties in CardKeyProviderCsv. Also having the coresponding
  encryption code somewhere out of tree may be confusing. Let's improve
  the design and put encryption and decryption functions in a single
  class. Let's also make sure the encryption/decryption is covered by
  unittests.

Related: SYS#7725
Change-Id: I180457d4938f526d227c81020e4e03c6b3a57dab
2025-11-21 17:49:09 +01:00
Harald Welte
52df66cd56 pySim.esim.es8p: Support non-operational ProfileMetadata
If no profileClass is given, ProfileMetadata defaults to operational.
Let's add the capability to also generate metadata for test or provisioning profiles.

Change-Id: Id55537ed03e2690c1fc9545bb3c49cfc76d8e331
2025-11-21 11:41:29 +00:00
Philipp Maier
4f75aa1c8f card_key_provider: fix sourcecode formatting
Change-Id: I5675f9f087086646937ca077d3545d2729ccd812
2025-11-18 14:08:42 +01:00
Philipp Maier
f94f366cf9 runtime: check record/file size before write
When writing data to a transparent or linear fixed (record oriented)
and the data to write exceeds the record/file size, then the UICC will
respond with an error "6700: Checking errors - Wrong length"

In particular when the data is supplied as a JSON object and not as a
hex string, it may not be immediately obvious to the average user what
the problem actually is.

Let's check the record/file size before writing the data and raise an
exception in case the data excieeds the record/file size. Let's also
print an informative string message in case the data length is less
than the record/file size to make the user aware of unwritten bytes
at the end of a record/file.

Related: OS#6864
Change-Id: I7fa717d803ae79398d2c5daf92a7336be660c5ad
2025-10-28 13:39:35 +01:00
Philipp Maier
4429e1cc70 pySim-shell: add a logger class to centralize logging
In many sub modules we still use print() to occassionally print status
messages or warnings. This technically does not hurt, but it is an unclean
solution which we should replace with something more mature.

Let's use python's built in logging framework to create a static logger
class that fits our needs. To maintain compatibility let's also make sure
that the logger class will behave like a normal print() statement when no
configuration parameters are supplied by the API user.

To illustrate how the approach can be used in sub-modules, this patch
replaces the print statements in runtime.py. The other print statements
will the be fixed in follow-up patches.

Related: OS#6864
Change-Id: I187f117e7e1ccdb2a85dfdfb18e84bd7561704eb
2025-10-25 19:46:34 +00:00
Philipp Maier
1ab2f8dd9d commands: do not use b2h with a string
The function h2b expects a bytearray and must not be used on a string.
This is also true for nullstrings ('').

Related: OS#6869
Change-Id: I0e28e6ec476901bf19aa0f8640e41c74aa6e3aa2
2025-10-21 17:17:21 +02:00
Harald Welte
947154639c pySim.esim.saip.FsNodeADF: Fix __str__ method
It's quite common for a FsNodeADF to not have a df_name, so we need
to guard against that during stringification to avoid an exception.

Change-Id: I919d7c46575e0ebcdf3b979347a5cdd1a9feb294
2025-09-24 17:59:17 +00:00
Kian-Meng Ang
4ee99c18cd Fix typos
Found via `codespell -S tests -L ist,adn,ciph,ue,ot,readd,te,oce,tye`

Change-Id: I00a72e4f479dcef88f7d1058ce53edd0129d336a
2025-09-24 17:59:17 +00:00
Eric Wild
5d2e2ee259 bsp: fix maxpayloadsize
Change-Id: I08f544877b79681ad1f758a1ca31c292eae9f868
2025-09-24 15:04:36 +00:00
Bjoern Riemer
caa955b3ac Identify cards by Historical bytes of ATR
- try to identify the CardModel by just comparing the Historical Bytes if matching by Whole ATR failed
- add decompose ATR code from pyscard-contrib

Related: OS#6837
Change-Id: Id7555e42290d232a0e0efc47e7d97575007d846f
2025-08-28 21:44:24 +00:00
Bjoern Riemer
4dddcf932a Make sure to select MF before probing for files/Addons
Change-Id: I685367c282f57a8856668a3172a9391a5bbcf2e2
2025-08-28 21:44:24 +00:00
Eric Wild
6cffb31b42 memory backed ephermal session store for easy concurrent runs
Change-Id: I05bfd6ff471ccf1c8c2b5f2b748b9d4125ddd4f7
2025-08-15 13:04:02 +02:00
Eric Wild
7798ea9c5c x509 cert: fix weird cert check
Change-Id: I18beab0e1b24579724704c4141a2c457b2d4cf99
2025-08-15 13:04:02 +02:00
Eric Wild
0b1d3c85fd smdpp: less verbose by default
Those data blobs are huge.

Change-Id: I04a72b8f52417862d4dcba1f0743700dd942ef49
2025-08-15 13:04:02 +02:00
Harald Welte
c7c48718ba Get rid of [now] superfluous HexAdapter
With the introduction of using osmocom.construct.{Bytes,GreedyBytes}
in Change-Id I1c8df6350c68aa408ec96ff6cd1e405ceb1a4fbb we don't have a
need for wrapping each instance of Bytes or GreedyBytes into a
HexAdapter anymore.  The osmocom.construct.{Bytes,GreedyBytes} will
automatically perform the related hex-string-to-bytes conversion if
needed - and during printing we have osmocom.utils.JsonEncoder that
makes sure to convert any bytes type to a hex-string.

Change-Id: I9c77e420c314f5e74458628dc4e767eab6d97123
2025-05-07 19:35:54 +02:00
Harald Welte
e37cdbcd3e docs: Better python doc-strings for better pySim.esim manual
Change-Id: I7be6264c665a2a25105681bb5e72d0f6715bbef8
2025-05-07 10:50:47 +02:00
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
d838a95c2a edit_{binary,record}_decoded: Support hex-decode of bytes
We've created + used osmocom.utils.JsonEncoder as an encoder class
for json.{dump,dumps} for quite some time.  However, we missed to
use this decoder class from the edit_{binary,record}_decoded commands
in the pySim-shell VTY.

Change-Id: I158e028f9920d8085cd20ea022be2437c64ad700
Related: OS#6774
2025-04-24 13:47:06 +00:00
Vadim Yanitskiy
aace546900 filesystem: fix WARNING: Block quote ends without a blank line
Use the 'r' (raw) qualifier to avoid rendering '\n' as the actual
line break in the auto-generated documentation.

Change-Id: Ie7f59685a78534eb2c43ec4bc39685d3fd264778
2025-04-24 02:50:27 +07:00
Philipp Maier
d5da431fd4 saip-tool: add commandline option to edit mandatory services list
Change-Id: I120b98d4b0942c26674bc1365c5711101ec95235
2025-04-16 10:35:15 +02:00
Philipp Maier
59faa02f9a ara_m: add command to lock write access to the ARA-M rules.
Recent versions of the ARA-M applet from Bertrand Martel can lock
the write access to ARA-M rules. Let's add a command for that and
some documentation.

Related: SYS#7245
Change-Id: I71581a0c9f146f9a0921093d9b53b053b4a8946c
2025-04-14 11:14:36 +00:00
Philipp Maier
1dea0f39dc saip-tool: add features to add, remove and inspect application PEs
The PE-Application object is used to provision JAVA-card applications
into an eUICC during profile installation. Let's extend the SAIP-tool
so that we are able to add, remove and inspect applications.

Change-Id: I41db96f2f0ccc29c1725a92215ce6b17d87b76ce
2025-04-14 11:01:24 +00:00
Harald Welte
a2bfd397ba pySim-smpp2sim.py: Simulate SMSC+CN+RAN+UE for OTA testing
The pySim-smpp2sim.py program exposes two interfaces:
* SMPP server-side port, so external programs can rx/tx SMS
* APDU interface towards the SIM card

It therefore emulates the SMSC, Core Network, RAND and UE parts
that would normally be encountered in an OTA setup.

Change-Id: Ie5bae9d823bca6f6c658bd455303f63bace2258c
2025-04-08 18:14:18 +00:00
Philipp Maier
40e795a825 saip-tool: add ProfileElement class for application PE
The application profile element has no ProfileElement class yet, so
let's create a ProfileElementApplication class and move the existing
extract-apps code into a method of ProfileElementApplication.

Change-Id: Iaa43036d388fbf1714c53cab1fc21092c4667a21
2025-03-31 12:27:24 +02:00
Harald Welte
701e011e14 [cosmetic] pySim.transport: Fix spelling/typos in comment
Change-Id: Ia20cc2439bf00c1b6479f36c05514945ac4faf71
2025-03-28 09:13:11 +01:00
Harald Welte
f57f6a95a5 pySim/commands: Fix envelope command APDU case after T=1 support
When we merged I8b56d7804a2b4c392f43f8540e0b6e70001a8970 for T=1
support, the ENVELOPE C-APDU was not adjusted to reflect the correct
case.  ENVELOPE expects a response and hence needs a Le byte present.

This avoids below related message when performing e.g. OTA via SMS

  Warning: received unexpected response data, incorrect APDU-case (3, should be 4, missing Le field?)!

Change-Id: Ice12675e02aa5438cf9f069f8fcc296c64aabc5a
Related: OS#6367
2025-03-28 09:13:11 +01:00
Philipp Maier
8da8b20f58 es8p: fix typo
Change-Id: I241efe0c7ceab190b7729a6d88101501ca37652e
2025-03-10 19:16:20 +00:00
Philipp Maier
74be2e202f filesystem: do not decode short TransRecEF records
A TransRecEF is based on a TransparentEF. This means that a TransRecEF
is basically normal TransparentEF that holds a record oriented data
structure. This also requires that the total length of the TransRecEF
is a multiple of the record length of the data structure that is stored
in it. When this is not the case, the last record will be cut short and
the decoding will fail. We should guard against this case.

Related: OS#6598
Change-Id: Ib1dc4d7ce306f1f0b080bb4b6abc36e72431d3fa
2025-03-10 18:59:08 +00:00
Neels Hofmeyr
cabb8edd53 pylint: ota.py: fix E0606 possibly-used-before-assignment
************* Module pySim.ota
pySim/ota.py:430:24: E0606: Possibly using variable 'cpl' before assignment (possibly-used-before-assignment)

Change-Id: Ibbae851e458bbe7426a788b0784d553753c1056f
2025-03-07 21:27:01 +01:00
Neels Hofmeyr
19e1330ce8 pylint: personalization.py: fix E1135: permitted_len unsupported-membership-test
pre-empt this from coming up in patch
I60ea8fd11fb438ec90ddb08b17b658cbb789c051:

E1135: Value 'self.permitted_len' doesn't support membership test (unsupported-membership-test) pickermitted_len

Change-Id: I0343f8dbbffefb4237a1cb4dd40b576f16111073
2025-03-07 21:26:54 +01:00
Harald Welte
de91b0dc97 euicc: Add euicc_memory_reset shell command
This implements the ES10c eUICC Memory Reset procedure

Change-Id: Ib462f5b7de3e500e51c0f3d6e2b9b0c2d3ba7e20
2025-02-14 12:32:41 +01:00
Philipp Maier
edcd62435d pySim/transport: add abstract get_atr method to LinkBase
The implementations that inheret from the LinkBase class are expected to
implement a get_atr method. This method is mandatory, since it is one of
the most basic functionalities of pySim to display an ATR. Also the ATR
is sometimes needed to distinguish between different card models.

The modem_atcmd and calypso implementation completely lack the get_atr
method. Apparantly it is not possible to get an ATR in those
environments, so lets add a dummy method there.

Related: OS#6322
Change-Id: I4fc020ca45658af78e495a5c1b985213f83cbb50
2025-01-29 13:35:44 +01:00
Harald Welte
08ba187fd4 ATR: align get_atr() return value type
type annotations claimed the return type was Hexstr, but in reality
it was a list of integers.  Let's fix that.

Change-Id: I01b247dad40ec986cf199302f8e92d16848bd499
Closes: OS#6322
2025-01-29 13:00:53 +01:00
Philipp Maier
d871e4696f ATR: use lowercase hex strings without spaces as ATR constants
The ATR constants are the only hex string constants where the hex
bytes digits are separated with spaces. Also the hex digits are in
lowercase. Let's use a lowercase string without spaces here like
we do in many other code locations.

Related: OS#6322
Change-Id: I95118115b02523ed262a2fbe4369ace3996cd8f5
2025-01-29 11:26:54 +01:00
Philipp Maier
15140aae44 global_platform: add new command "install_cap"
Installing JAVA-card applets from a CAP file is a multi step process, which is
difficult when done manually. Fortunately it is easy to automate the process,
so let's add a dedicated command for that.

Change-Id: I6cbd37f0fad5579b20e83c27349bd5acc129e6d0
Related: OS#6679
2025-01-22 16:46:32 +01:00
Harald Welte
a0071b32ff global_platform: LOAD and INSTALL [for load] support
In this patch we add the commands "install_for_load" and "load".

Depends: pyosmocom.git I86df064fa41db85923eeb0d83cc399504fdd4488
Change-Id: I924aaeecbb3a72bdb65eefbff6135e4e9570579e
Related: OS#6679
2025-01-22 15:42:09 +01:00