laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/42189?usp=email )
Change subject: tests/pySim-smpp2sim_test: add testcases for AES128 and AES256
......................................................................
tests/pySim-smpp2sim_test: add testcases for AES128 and AES256
Extend the existing test script so that it can handle multiple
testcases. Also add support for switching eUICC profiles.
Finally, add a testcases to test OTA-SMS (RFM) with AES128 and
AES256 encryption.
Change-Id: I1f10504f3a29a8c74a17991632d932819fecfa5a
Related: OS#6868
---
D tests/pySim-smpp2sim_test/pySim-smpp2sim_test.cfg
M tests/pySim-smpp2sim_test/pySim-smpp2sim_test.sh
A tests/pySim-smpp2sim_test/testcase_3des_cbc2_rfm.cfg
A tests/pySim-smpp2sim_test/testcase_aes128_cbc_cmac_rfm.cfg
A tests/pySim-smpp2sim_test/testcase_aes256_cbc_cmac_rfm.cfg
5 files changed, 161 insertions(+), 46 deletions(-)
Approvals:
daniel: Looks good to me, but someone else must approve
Jenkins Builder: Verified
laforge: Looks good to me, approved
diff --git a/tests/pySim-smpp2sim_test/pySim-smpp2sim_test.cfg b/tests/pySim-smpp2sim_test/pySim-smpp2sim_test.cfg
deleted file mode 100644
index 1c2a953..0000000
--- a/tests/pySim-smpp2sim_test/pySim-smpp2sim_test.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
-# Card parameter:
-ICCID="8949440000001155314"
-KIC='51D4FC44BCBA7C4589DFADA3297720AF'
-KID='0449699C472CE71E2FB7B56245EF7684'
-
-# Testcase: Send OTA-SMS that selects DF.GSM and returns the select response
-TAR='B00010'
-APDU='A0A40000027F20A0C0000016'
-EXPECTED_RESPONSE='0000ffff7f2002000000000009b106350400838a838a 9000'
\ No newline at end of file
diff --git a/tests/pySim-smpp2sim_test/pySim-smpp2sim_test.sh b/tests/pySim-smpp2sim_test/pySim-smpp2sim_test.sh
index 2ca0a9e..0881319 100755
--- a/tests/pySim-smpp2sim_test/pySim-smpp2sim_test.sh
+++ b/tests/pySim-smpp2sim_test/pySim-smpp2sim_test.sh
@@ -20,13 +20,14 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+PYSIM_SHELL=./pySim-shell.py
+PYSIM_SHELL_LOG=./pySim-shell.log
PYSIM_SMPP2SIM=./pySim-smpp2sim.py
PYSIM_SMPP2SIM_LOG=./pySim-smpp2sim.log
PYSIM_SMPP2SIM_PORT=2775
PYSIM_SMPP2SIM_TIMEOUT=10
PYSIM_SMPPOTATOOL=./contrib/smpp-ota-tool.py
PYSIM_SMPPOTATOOL_LOG=./smpp-ota-tool.log
-PYSIM_SHELL=./pySim-shell.py
function dump_logs {
echo ""
@@ -44,12 +45,11 @@
function send_test_request {
echo ""
echo "Sending request to SMPP server:"
- TAR=$1
- C_APDU=$2
- R_APDU_EXPECTED=$3
+ C_APDU=$1
+ R_APDU_EXPECTED=$2
echo "Sending: $C_APDU"
- COMMANDLINE="$PYSIM_SMPPOTATOOL --verbose --port $PYSIM_SMPP2SIM_PORT --kic $KIC --kid $KID --tar $TAR --apdu $C_APDU"
+ COMMANDLINE="$PYSIM_SMPPOTATOOL --verbose --port $PYSIM_SMPP2SIM_PORT --kic $KIC --kid $KID --kic_idx $KEY_INDEX --kid_idx $KEY_INDEX --algo-crypt $ALGO_CRYPT --algo-auth $ALGO_AUTH --tar $TAR --apdu $C_APDU"
echo "Commandline: $COMMANDLINE"
R_APDU=`$COMMANDLINE 2> $PYSIM_SMPPOTATOOL_LOG`
if [ $? -ne 0 ]; then
@@ -57,7 +57,7 @@
dump_logs
exit 1
fi
-
+ echo ""
echo "Got response from SMPP server:"
echo "Sent: $C_APDU"
echo "Received: $R_APDU"
@@ -68,16 +68,14 @@
exit 1
fi
echo "Response matches the expected response -- success!"
- echo ""
}
function start_smpp_server {
PCSC_READER=$1
-
- # Start the SMPP server
echo ""
echo "Starting SMPP server:"
+ # Start the SMPP server
COMMANDLINE="$PYSIM_SMPP2SIM -p $PCSC_READER --smpp-bind-port $PYSIM_SMPP2SIM_PORT --apdu-trace"
echo "Commandline: $COMMANDLINE"
$COMMANDLINE > $PYSIM_SMPP2SIM_LOG 2>&1 &
@@ -102,55 +100,117 @@
echo "SMPP server reachable (port=$PYSIM_SMPP2SIM_PORT)"
}
-function find_card_by_iccid {
- # Find reader number of the card
- ICCID=$1
+function stop_smpp_server {
+ echo ""
+ echo "Stopping SMPP server:"
+ kill $PYSIM_SMPP2SIM_PID
+ echo "SMPP server stopped (PID=$PYSIM_SMPP2SIM_PID)"
+ trap EXIT
+}
+function find_card_by_iccid_or_eid {
+ ICCID=$1
+ EID=$2
echo ""
echo "Searching for card:"
echo "ICCID: \"$ICCID\""
+ if [ -n "$EID" ]; then
+ echo "EID: \"$EID\""
+ fi
+ # Determine number of available PCSC readers
+ PCSC_READER_COUNT=`pcsc_scan -rn | wc -l`
+
+ # In case an EID is set, search for a card with that EID first
+ if [ -n "$EID" ]; then
+ for PCSC_READER in $(seq 0 $(($PCSC_READER_COUNT-1))); do
+ echo "probing card (eID) in reader $PCSC_READER ..."
+ RESULT_JSON=`$PYSIM_SHELL -p $PCSC_READER --noprompt -e "select ADF.ISD-R" -e "get_eid" 2> /dev/null | tail -3`
+ echo $RESULT_JSON | grep $EID > /dev/null
+ if [ $? -eq 0 ]; then
+ echo "Found card (eID) in reader $PCSC_READER"
+ return $PCSC_READER
+ fi
+ done
+ fi
+
+ # Search for card with the given ICCID
if [ -z "$ICCID" ]; then
echo "invalid ICCID, zero length ICCID is not allowed! -- abort"
exit 1
fi
-
- PCSC_READER_COUNT=`pcsc_scan -rn | wc -l`
for PCSC_READER in $(seq 0 $(($PCSC_READER_COUNT-1))); do
- echo "probing card in reader $PCSC_READER ..."
- EF_ICCID_DECODED=`$PYSIM_SHELL -p $PCSC_READER --noprompt -e 'select EF.ICCID' -e 'read_binary_decoded --oneline' 2> /dev/null | tail -1`
- echo $EF_ICCID_DECODED | grep $ICCID > /dev/null
+ echo "probing card (ICCID) in reader $PCSC_READER ..."
+ RESULT_JSON=`$PYSIM_SHELL -p $PCSC_READER --noprompt -e "select EF.ICCID" -e "read_binary_decoded" 2> /dev/null | tail -3`
+ echo $RESULT_JSON | grep $ICCID > /dev/null
if [ $? -eq 0 ]; then
- echo "Found card in reader $PCSC_READER"
+ echo "Found card (by ICCID) in reader $PCSC_READER"
return $PCSC_READER
fi
done
- echo "Card with ICCID \"$ICCID\" not found -- abort"
+ echo "Card not found -- abort"
exit 1
}
+function enable_profile {
+ PCSC_READER=$1
+ ICCID=$2
+ EID=$3
+ if [ -z "$EID" ]; then
+ # This is no eUICC, nothing to enable
+ return 0
+ fi
+
+ # Check if the profile is already enabled
+ RESULT_JSON=`$PYSIM_SHELL -p $PCSC_READER --noprompt -e "select EF.ICCID" -e "read_binary_decoded" 2> /dev/null | tail -3`
+ ICCID_ENABLED=`echo $RESULT_JSON | jq -r '.iccid'`
+ if [ $ICCID != $ICCID_ENABLED ]; then
+ # Disable the currentle enabled profile
+ echo ""
+ echo "Disabeling currently enabled profile:"
+ echo "ICCID: \"$ICCID\""
+ RESULT_JSON=`$PYSIM_SHELL -p $PCSC_READER --noprompt -e "select ADF.ISD-R" -e "disable_profile --iccid $ICCID_ENABLED" 2> /dev/null | tail -3`
+ echo $RESULT_JSON | grep "ok" > /dev/null
+ if [ $? -ne 0 ]; then
+ echo "unable to disable profile with \"$ICCID_ENABLED\""
+ exit 1
+ fi
+ echo "profile disabled"
+
+ # Enable the profile we intend to test with
+ echo ""
+ echo "Enabeling profile:"
+ echo "ICCID: \"$ICCID\""
+ RESULT_JSON=`$PYSIM_SHELL -p $PCSC_READER --noprompt -e "select ADF.ISD-R" -e "enable_profile --iccid $ICCID" 2> /dev/null | tail -3`
+ echo $RESULT_JSON | grep "ok\|profileNotInDisabledState" > /dev/null
+ if [ $? -ne 0 ]; then
+ echo "unable to enable profile with \"$ICCID\""
+ exit 1
+ fi
+ echo "profile enabled"
+ fi
+}
+
export PYTHONPATH=./
echo "pySim-smpp2sim_test - a test program to test pySim-smpp2sim.py"
echo "=============================================================="
-# TODO: At the moment we can only have one card and one testcase. This is
-# sufficient for now. We can extend this later as needed.
+TESTCASE_DIR=`dirname $0`
+for TEST_CONFIG_FILE in $TESTCASE_DIR/testcase_*.cfg ; do
+ echo ""
+ echo "running testcase: $TEST_CONFIG_FILE"
+ . $TEST_CONFIG_FILE
+ find_card_by_iccid_or_eid $ICCID $EID
+ PCSC_READER=$?
+ enable_profile $PCSC_READER $ICCID $EID
+ start_smpp_server $PCSC_READER
+ send_test_request $APDU "$EXPECTED_RESPONSE"
+ stop_smpp_server
+ echo ""
+ echo "testcase ok"
+ echo "--------------------------------------------------------------"
+done
-# Read test parameters from config from file
-TEST_CONFIG_FILE=${0%.*}.cfg
-echo "using config file: $TEST_CONFIG_FILE"
-if ! [ -e "$TEST_CONFIG_FILE" ]; then
- echo "test configuration file does not exist! -- abort"
- exit 1
-fi
-. $TEST_CONFIG_FILE
-
-# Execute testcase
-find_card_by_iccid $ICCID
-start_smpp_server $?
-send_test_request $TAR $APDU "$EXPECTED_RESPONSE"
-
-
-
+echo "done."
diff --git a/tests/pySim-smpp2sim_test/testcase_3des_cbc2_rfm.cfg b/tests/pySim-smpp2sim_test/testcase_3des_cbc2_rfm.cfg
new file mode 100644
index 0000000..e056490
--- /dev/null
+++ b/tests/pySim-smpp2sim_test/testcase_3des_cbc2_rfm.cfg
@@ -0,0 +1,17 @@
+# Preparation:
+# This testcase executes against a sysmoISIM-SJA5 card. For the testcase, the
+# key configuration on the card may be used as it is.
+
+# Card parameter:
+ICCID="8949440000001155314" # <-- change to the ICCID of your card!
+EID=""
+KIC='51D4FC44BCBA7C4589DFADA3297720AF' # <-- change to the KIC1 of your card!
+KID='0449699C472CE71E2FB7B56245EF7684' # <-- change to the KID1 of your card!
+KEY_INDEX=1
+ALGO_CRYPT=triple_des_cbc2
+ALGO_AUTH=triple_des_cbc2
+TAR='B00010'
+
+# Testcase: Send OTA-SMS that selects DF.GSM and returns the select response
+APDU='A0A40000027F20A0C0000016'
+EXPECTED_RESPONSE='0000ffff7f2002000000000009b106350400838a838a 9000'
diff --git a/tests/pySim-smpp2sim_test/testcase_aes128_cbc_cmac_rfm.cfg b/tests/pySim-smpp2sim_test/testcase_aes128_cbc_cmac_rfm.cfg
new file mode 100644
index 0000000..cfd0ef5
--- /dev/null
+++ b/tests/pySim-smpp2sim_test/testcase_aes128_cbc_cmac_rfm.cfg
@@ -0,0 +1,19 @@
+# Preparation:
+# This testcase executes against a sysmoEUICC1-C2T, which is equipped with the
+# TS48V1-B-UNIQUE test profile from https://test.rsp.sysmocom.de/ (Activation
+# code: 1$smdpp.test.rsp.sysmocom.de$TS48V1-B-UNIQUE). This testprofile must be
+# present on the eUICC before this testcase can be executed.
+
+# Card parameter:
+ICCID="8949449999999990031"
+EID="89049044900000000000000000102355" # <-- change to the EID of your card!
+KIC='66778899aabbccdd1122334455eeff10'
+KID='112233445566778899aabbccddeeff10'
+KEY_INDEX=2
+ALGO_CRYPT=aes_cbc
+ALGO_AUTH=aes_cmac
+TAR='b00120'
+
+# Testcase: Send OTA-SMS that selects DF.ICCID and returns the select response
+APDU='00a40004022fe200C000001d'
+EXPECTED_RESPONSE='621b8202412183022fe2a503d001408a01058b032f06038002000a8800 9000'
\ No newline at end of file
diff --git a/tests/pySim-smpp2sim_test/testcase_aes256_cbc_cmac_rfm.cfg b/tests/pySim-smpp2sim_test/testcase_aes256_cbc_cmac_rfm.cfg
new file mode 100644
index 0000000..0bffbbe
--- /dev/null
+++ b/tests/pySim-smpp2sim_test/testcase_aes256_cbc_cmac_rfm.cfg
@@ -0,0 +1,28 @@
+# Preparation:
+# This testcase executes against a sysmoISIM-SJA5 card. Since this card model is
+# shipped with a classic DES key configuration, it is necessary to provision
+# AES128 test keys before this testcase may be executed. The the following
+# pySim-shell command sequence may be used:
+#
+# verify_adm 34173960 # <-- change to the ADM key of your card!
+# select /DF.SYSTEM/EF.0348_KEY
+# update_record 10 fe03601111111111111111111111111111111111111111111111111111111111111111
+# update_record 11 fe03612222222222222222222222222222222222222222222222222222222222222222
+# update_record 12 fe03623333333333333333333333333333333333333333333333333333333333333333
+#
+# This overwrites one of the already existing 3DES SCP02 key (KVN 47) and replaces it
+# with an AES256 SCP80 key (KVN 3).
+
+# Card parameter:
+ICCID="8949440000001155314" # <-- change to the ICCID of your card!
+EID=""
+KIC='1111111111111111111111111111111111111111111111111111111111111111'
+KID='2222222222222222222222222222222222222222222222222222222222222222'
+KEY_INDEX=3
+ALGO_CRYPT=aes_cbc
+ALGO_AUTH=aes_cmac
+TAR='B00010'
+
+# Testcase: Send OTA-SMS that selects DF.GSM and returns the select response
+APDU='A0A40000027F20A0C0000016'
+EXPECTED_RESPONSE='0000ffff7f2002000000000009b106350400838a838a 9000'
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/42189?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I1f10504f3a29a8c74a17991632d932819fecfa5a
Gerrit-Change-Number: 42189
Gerrit-PatchSet: 6
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <dwillmann(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: lynxis lazus <lynxis(a)fe80.eu>
laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/42237?usp=email )
Change subject: docs/smpp-ota-tool: Add documentation/tutorial
......................................................................
docs/smpp-ota-tool: Add documentation/tutorial
We already have documentation that explains how to run pySim-smpp2sim.
With smpp-ota-tool we now have a counterpart for pySim-smpp2sim, so
let's add documentation for this tool as well.
Related: SYS#7881
Change-Id: If0d18a263f5a6dc035b90f5c5c6a942d46bbba49
---
M docs/index.rst
A docs/smpp-ota-tool.rst
M docs/smpp2sim.rst
3 files changed, 182 insertions(+), 0 deletions(-)
Approvals:
laforge: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/docs/index.rst b/docs/index.rst
index 92be830..a6ed7b9 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -48,6 +48,7 @@
sim-rest
suci-keytool
saip-tool
+ smpp-ota-tool
Indices and tables
diff --git a/docs/smpp-ota-tool.rst b/docs/smpp-ota-tool.rst
new file mode 100644
index 0000000..beb494a
--- /dev/null
+++ b/docs/smpp-ota-tool.rst
@@ -0,0 +1,179 @@
+smpp-ota-tool
+=============
+
+The `smpp-ota-tool` allows users to send OTA SMS messages containing APDU scripts (RFM, RAM) via an SMPP server. The
+intended audience are developers who want to test/evaluate the OTA SMS interface of a SIM/UICC/eUICC. `smpp-ota-tool`
+is intended to be used as a companion tool for :ref:`pySim-smpp2sim`, however it should be usable on any other SMPP
+server (such as a production SMSC of a live cellular network) as well.
+
+From the technical perspective `smpp-ota-tool` takes the role of an SMPP ESME. It takes care of the encoding, encryption
+and checksumming (signing) of the RFM/RAM OTA SMS and eventually submits it to the SMPP server. The program then waits
+for a response. The response is automatically parsed and printed on stdout. This makes the program also suitable to be
+called from shell scripts.
+
+.. note:: In the following we will we will refer to `SIM` as one of the following: `SIM`, `USIM`, `ISIM`, `UICC`,
+ `eUICC`, `eSIM`.
+
+Applying OTA keys
+~~~~~~~~~~~~~~~~~
+
+Depending on the `SIM` type you will receive one or more sets of keys which you can use to communicate with the `SIM`
+through a secure channel protocol. When using the OTA SMS method, the SCP80 protocol is used and it therefore crucial
+to use a keyset that is actually suitable for SCP80.
+
+A keyset usually consists of three keys:
+
+#. KIC: the key used for ciphering (encryption/decryption)
+#. KID: the key used to compute a cryptographic checksum (signing)
+#. KIK: the key used to encrypt/decrypt key material (key rotation, adding of new keys)
+
+From the transport security perspective, only KIC and KID are relevant. The KIK (also referenced as "Data Encryption
+Key", DEK) is only used when keys are rotated or new keys are added (see also ETSI TS 102 226, section 8.2.1.5).
+
+When the keyset is programmed into the security domain of the `SIM`, it is tied to a specific cryptographic algorithm
+(3DES, AES128 or AES256) and a so called Key Version Number (KVN). The term "Key Version Number" is misleading, since
+it is actually not a version number. It is a unique identifier of a certain keyset which also identifies for which
+secure channel protocol the keyset may be used. Keysets with a KVN from 1-15 (``0x01``-``0x0F``) are suitable for SCP80.
+This means that it is not only important to know just the KIC/KID/KIK keys. Also the related algorithms and the KVN
+numbers must be known.
+
+.. note:: SCP80 keysets typically start counting from 1 upwards. Typical configurations use a set of 3 keysets with
+ KVN numbers 1-3.
+
+Addressing an Application
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When communicating with a specific application on a `SIM` via SCP80, it is important to address that application with
+the correct parameters. The following two parameters must be known in advance:
+
+#. TAR: The Toolkit Application Reference (TAR) number is a three byte value that uniquely addresses an application
+ on the `SIM`. The exact values may vary (see also ETSI TS 101 220, Table D.1).
+#. MSL: The Minimum Security Level (MSL) is a bit-field that dictates which of the security measures encoded in the
+ SPI are mandatory (see also ETSI TS 102 225, section 5.1.1).
+
+A practical example
+~~~~~~~~~~~~~~~~~~~
+
+.. note:: This tutorial assumes that pySim-smpp2sim is running on the local machine with its default parameters.
+ See also :ref:`pySim-smpp2sim`.
+
+Let's assume that an OTA SMS shall be sent to the SIM RFM application of an sysmoISIM-SJA2. What we want to do is to
+select DF.GSM and to get the select response back.
+
+We have received the following key material from the `SIM` vendor:
+
+::
+
+ KIC1: F09C43EE1A0391665CC9F05AF4E0BD10
+ KID1: 01981F4A20999F62AF99988007BAF6CA
+ KIK1: 8F8AEE5CDCC5D361368BC45673D99195
+ KIC2: 01022916E945B656FDE03F806A105FA2
+ KID2: D326CB69F160333CC5BD1495D448EFD6
+ KIK2: 08037E0590DFE049D4975FFB8652F625
+ KIC3: 2B22824D0D27A3A1CEEC512B312082B4
+ KID3: F1697766925A11F4458295590137B672
+ KIK3: C7EE69B2C5A1C8E160DD36A38EB517B3
+
+Those are three keysets. The enumeration is directly equal to the KVN used. All three keysets are 3DES keys, which
+means triple_des_cbc2 is the correct algorithm to use.
+
+.. note:: The key set configuration can be confirmed by retrieving the key configuration using
+ `get_data key_information` from within an SCP02 session on ADF.ISD.
+
+In this example we intend to address the SIM RFM application on the `SIM`. Which according to the manual has TAR ``B00010``
+and MSL ``0x06``. When we hold ``0x06`` = ``0b00000110`` against the SPI coding chart (see also ETSI TS 102 225,
+section 5.1.1). We can deduct that Ciphering and Cryptographic Checksum are mandatory.
+
+.. note:: The MSL (see also ETSI TS 102 226, section 6.1) is assigned to an application by the `SIM` issuer. It is a
+ custom decision and may vary with different `SIM` types/profiles. In the case of sysmoISIM-SJS1/SJA2/SJA5 the
+ counter requirement has been waived to simplify lab/research type use. In productive environments, `SIM`
+ applications should ideally use an MSL that makes the counter mandatory.
+
+In order to select DF.GSM (``0x7F20``) and to retrieve the select response, two APDUs are needed. The first APDU is the
+select command ``A0A40000027F20`` and the second is the related get-response command ``A0C0000016``. Those APDUs will be
+concatenated and are sent in a single message. The message containing the concatenated APDUs works as a script that
+is received by the SIM RFM application and then executed. This method poses some limitations that have to be taken into
+account when making requests like this (see also ETSI TS 102 226, section 5).
+
+With this information we may now construct a commandline for `smpp-ota-tool.py`. We will pass the KVN as kid_idx and
+kic_idx (see also ETSI TS 102 225, Table 2, fields `KIc` and `KID`). Both index values should refer to the same
+keyset/KVN as keysets should not be mixed. (`smpp-ota-tool` still provides separate parameters anyway to allow testing
+with invalid keyset combinations)
+
+::
+
+ $ PYTHONPATH=./ ./contrib/smpp-ota-tool.py --kic F09C43EE1A0391665CC9F05AF4E0BD10 --kid 01981F4A20999F62AF99988107BAF6CA --kid_idx 1 --kic_idx 1 --algo-crypt triple_des_cbc2 --algo-auth triple_des_cbc2 --tar B00010 --apdu A0A40000027F20 --apdu A0C0000016
+ 2026-02-26 17:13:56 INFO Connecting to localhost:2775...
+ 2026-02-26 17:13:56 INFO C-APDU sending: a0a40000027f20a0c0000016...
+ 2026-02-26 17:13:56 INFO SMS-TPDU sending: 02700000281506191515b00010da1d6cbbd0d11ce4330d844c7408340943e843f67a6d7b0674730881605fd62d...
+ 2026-02-26 17:13:56 INFO SMS-TPDU sent, waiting for response...
+ 2026-02-26 17:13:56 INFO SMS-TPDU received: 027100002c12b000107ddf58d1780f771638b3975759f4296cf5c31efc87a16a1b61921426baa16da1b5ba1a9951d59a39
+ 2026-02-26 17:13:56 INFO SMS-TPDU decoded: (Container(rpl=44, rhl=18, tar=b'\xb0\x00\x10', cntr=b'\x00\x00\x00\x00\x00', pcntr=0, response_status=uEnumIntegerString.new(0, 'por_ok'), cc_rc=b'\x8f\xea\xf5.\xf4\x0e\xc2\x14', secured_data=b'\x02\x90\x00\x00\x00\xff\xff\x7f \x02\x00\x00\x00\x00\x00\t\xb1\x065\x04\x00\x83\x8a\x83\x8a'), Container(number_of_commands=2, last_status_word=u'9000', last_response_data=u'0000ffff7f2002000000000009b106350400838a838a'))
+ 2026-02-26 17:13:56 INFO R-APDU received: 0000ffff7f2002000000000009b106350400838a838a 9000
+ 0000ffff7f2002000000000009b106350400838a838a 9000
+ 2026-02-26 17:13:56 INFO Disconnecting...
+
+The result we see is the select response of DF.GSM and a status word indicating that the last command has been
+processed normally.
+
+As we can see, this mechanism now allows us to perform small administrative tasks remotely. We can read the contents of
+files remotely or make changes to files. Depending on the changes we make, there may be security issues arising from
+replay attacks. With the commandline above, the communication is encrypted and protected by a cryptographic checksum,
+so an adversary can neither read, nor alter the message. However, an adversary could still replay an intercepted
+message and the `SIM` would happily execute the contained APDUs again.
+
+To prevent this, we may include a replay protection counter within the message. In this case, the MSL indicates that a
+replay protection counter is not required. However, to extended the security of our messages, we may chose to use a
+counter anyway. In the following example, we will encode a counter value of 100. We will instruct the `SIM` to make sure
+that the value we send is higher than the counter value that is currently stored in the `SIM`.
+
+To add a replay connection counter we add the commandline arguments `--cntr-req` to set the counter requirement and
+`--cntr` to pass the counter value.
+
+::
+
+ $ PYTHONPATH=./ ./contrib/smpp-ota-tool.py --kic F09C43EE1A0391665CC9F05AF4E0BD10 --kid 01981F4A20999F62AF99988107BAF6CA --kid_idx 1 --kic_idx 1 --algo-crypt triple_des_cbc2 --algo-auth triple_des_cbc2 --tar B00010 --apdu A0A40000027F20 --apdu A0C0000016 --cntr-req counter_must_be_higher --cntr 100
+ 2026-02-26 17:16:39 INFO Connecting to localhost:2775...
+ 2026-02-26 17:16:39 INFO C-APDU sending: a0a40000027f20a0c0000016...
+ 2026-02-26 17:16:39 INFO SMS-TPDU sending: 02700000281516191515b000103a4f599e94f2b5dcfbbda984761b7977df6514c57a580fb4844787c436d2eade...
+ 2026-02-26 17:16:39 INFO SMS-TPDU sent, waiting for response...
+ 2026-02-26 17:16:39 INFO SMS-TPDU received: 027100002c12b0001049fb0315f6c6401b553867f412cefaf9355b38271178edb342a3bc9cc7e670cdc1f45eea6ffcbb39
+ 2026-02-26 17:16:39 INFO SMS-TPDU decoded: (Container(rpl=44, rhl=18, tar=b'\xb0\x00\x10', cntr=b'\x00\x00\x00\x00d', pcntr=0, response_status=uEnumIntegerString.new(0, 'por_ok'), cc_rc=b'\xa9/\xc7\xc9\x00"\xab5', secured_data=b'\x02\x90\x00\x00\x00\xff\xff\x7f \x02\x00\x00\x00\x00\x00\t\xb1\x065\x04\x00\x83\x8a\x83\x8a'), Container(number_of_commands=2, last_status_word=u'9000', last_response_data=u'0000ffff7f2002000000000009b106350400838a838a'))
+ 2026-02-26 17:16:39 INFO R-APDU received: 0000ffff7f2002000000000009b106350400838a838a 9000
+ 0000ffff7f2002000000000009b106350400838a838a 9000
+ 2026-02-26 17:16:39 INFO Disconnecting...
+
+The `SIM` has accepted the message. The message got processed and the `SIM` has set its internal to 100. As an experiment,
+we may try to re-use the counter value:
+
+::
+
+ $ PYTHONPATH=./ ./contrib/smpp-ota-tool.py --kic F09C43EE1A0391665CC9F05AF4E0BD10 --kid 01981F4A20999F62AF99988107BAF6CA --kid_idx 1 --kic_idx 1 --algo-crypt triple_des_cbc2 --algo-auth triple_des_cbc2 --tar B00010 --apdu A0A40000027F20 --apdu A0C0000016 --cntr-req counter_must_be_higher --cntr 100
+ 2026-02-26 17:16:43 INFO Connecting to localhost:2775...
+ 2026-02-26 17:16:43 INFO C-APDU sending: a0a40000027f20a0c0000016...
+ 2026-02-26 17:16:43 INFO SMS-TPDU sending: 02700000281516191515b000103a4f599e94f2b5dcfbbda984761b7977df6514c57a580fb4844787c436d2eade...
+ 2026-02-26 17:16:43 INFO SMS-TPDU sent, waiting for response...
+ 2026-02-26 17:16:43 INFO SMS-TPDU received: 027100000b0ab0001000000000000006
+ 2026-02-26 17:16:43 INFO SMS-TPDU decoded: (Container(rpl=11, rhl=10, tar=b'\xb0\x00\x10', cntr=b'\x00\x00\x00\x00\x00', pcntr=0, response_status=uEnumIntegerString.new(6, 'undefined_security_error'), cc_rc=b'', secured_data=b''), None)
+ Traceback (most recent call last):
+ File "/home/user/work/git_master/pysim/./contrib/smpp-ota-tool.py", line 238, in <module>
+ resp, sw = smpp_handler.transceive_apdu(apdu, opts.src_addr, opts.dest_addr, opts.timeout)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "/home/user/work/git_master/pysim/./contrib/smpp-ota-tool.py", line 162, in transceive_apdu
+ raise ValueError("Response does not contain any last_response_data, no R-APDU received!")
+ ValueError: Response does not contain any last_response_data, no R-APDU received!
+ 2026-02-26 17:16:43 INFO Disconnecting...
+
+As we can see, the `SIM` has rejected the message with an `undefined_security_error`. The replay-protection-counter
+ensures that a message can only be sent once.
+
+.. note:: The replay-protection-counter is implemented as a 5 byte integer value (see also ETSI TS 102 225, Table 3).
+ When the counter has reached its maximum, it will not overflow nor can it be reset.
+
+smpp-ota-tool syntax
+~~~~~~~~~~~~~~~~~~~~
+
+.. argparse::
+ :module: contrib.smpp-ota-tool
+ :func: option_parser
+ :prog: contrib/smpp-ota-tool.py
diff --git a/docs/smpp2sim.rst b/docs/smpp2sim.rst
index cd86900..0ae64e7 100644
--- a/docs/smpp2sim.rst
+++ b/docs/smpp2sim.rst
@@ -55,3 +55,5 @@
SMSPPDownload(DeviceIdentities({'source_dev_id': 'network', 'dest_dev_id': 'uicc'}),Address({'ton_npi': 0, 'call_number': '0123456'}),SMS_TPDU({'tpdu': '400290217ff6227052000000002d02700000281516191212b0000127fa28a5bac69d3c5e9df2c7155dfdde449c826b236215566530787b30e8be5d'}))
INFO root: ENVELOPE: d147820283818604001032548b3b400290217ff6227052000000002d02700000281516191212b0000127fa28a5bac69d3c5e9df2c7155dfdde449c826b236215566530787b30e8be5d
INFO root: SW 9000: 027100002412b000019a551bb7c28183652de0ace6170d0e563c5e949a3ba56747fe4c1dbbef16642c
+
+.. note:: for sending OTA SMS messages :ref:`smpp-ota-tool` may be used.
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/42237?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: If0d18a263f5a6dc035b90f5c5c6a942d46bbba49
Gerrit-Change-Number: 42237
Gerrit-PatchSet: 4
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Attention is currently required from: dexter.
laforge has posted comments on this change by dexter. ( https://gerrit.osmocom.org/c/pysim/+/42235?usp=email )
Change subject: contrib/smpp-ota-tool: use '-' instead of '_' in command line args
......................................................................
Patch Set 2: Code-Review+2
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/42235?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: comment
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: Icbe9d753d59263997e9ca34d46ed0daca36ca16c
Gerrit-Change-Number: 42235
Gerrit-PatchSet: 2
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Attention: dexter <pmaier(a)sysmocom.de>
Gerrit-Comment-Date: Tue, 10 Mar 2026 09:22:54 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
Attention is currently required from: daniel, dexter.
laforge has posted comments on this change by dexter. ( https://gerrit.osmocom.org/c/pysim/+/42278?usp=email )
Change subject: tests/pySim-smpp2sim_test/card_sanitizer: update card backup with new test keyset
......................................................................
Patch Set 1: Code-Review+2
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/42278?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: comment
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I5aa8a413b19b3e43a79d03e904daab50b4b1e767
Gerrit-Change-Number: 42278
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <dwillmann(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Attention: daniel <dwillmann(a)sysmocom.de>
Gerrit-Attention: dexter <pmaier(a)sysmocom.de>
Gerrit-Comment-Date: Tue, 10 Mar 2026 09:22:11 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
Attention is currently required from: pespin.
lynxis lazus has posted comments on this change by lynxis lazus. ( https://gerrit.osmocom.org/c/osmo-asf4-dfu/+/42170?usp=email )
Change subject: dfu: mainloop: work on a local copy of dfu_state
......................................................................
Patch Set 4:
(1 comment)
Patchset:
PS4:
I could drop this commit in favor of the switch() case
--
To view, visit https://gerrit.osmocom.org/c/osmo-asf4-dfu/+/42170?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: comment
Gerrit-Project: osmo-asf4-dfu
Gerrit-Branch: master
Gerrit-Change-Id: Ic146c8fa5ba25425cf785bae66f9c99b0faab944
Gerrit-Change-Number: 42170
Gerrit-PatchSet: 4
Gerrit-Owner: lynxis lazus <lynxis(a)fe80.eu>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-CC: pespin <pespin(a)sysmocom.de>
Gerrit-Attention: pespin <pespin(a)sysmocom.de>
Gerrit-Comment-Date: Tue, 10 Mar 2026 09:11:36 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No